@@ -1,7 +1,7 @@  | 
            ||
| 1 | 1 | 
                github "Alamofire/Alamofire" "5.0.0.beta.1"  | 
            
| 2 | 
                -github "ReactiveX/RxSwift" "4.4.0"  | 
            |
| 2 | 
                +github "ReactiveX/RxSwift" "4.4.2"  | 
            |
| 3 | 3 | 
                github "RxSwiftCommunity/RxDataSources" "3.1.0"  | 
            
| 4 | 4 | 
                github "Yalantis/PullToRefresh" "3.1"  | 
            
| 5 | 
                -github "onevcat/Kingfisher" "5.1.0"  | 
            |
| 5 | 
                +github "onevcat/Kingfisher" "5.2.0"  | 
            |
| 6 | 6 | 
                github "stephencelis/SQLite.swift" "0.11.5"  | 
            
| 7 | 7 | 
                github "tristanhimmelman/ObjectMapper" "3.4.2"  | 
            
                @@ -24,7 +24,6 @@  | 
            ||
| 24 | 24 | 
                 		0505AD0D21DF34E100404071 /* CoreTelephony.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0505AD0021DF107D00404071 /* CoreTelephony.framework */; };
               | 
            
| 25 | 25 | 
                 		05130F4021C94B33004EF1BE /* PaiaiUIKit.h in Headers */ = {isa = PBXBuildFile; fileRef = 05130F3021C94B32004EF1BE /* PaiaiUIKit.h */; settings = {ATTRIBUTES = (Public, ); }; };
               | 
            
| 26 | 26 | 
                 		05130F4321C94B33004EF1BE /* PaiaiUIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 05130F2E21C94B32004EF1BE /* PaiaiUIKit.framework */; };
               | 
            
| 27 | 
                -		05130F4421C94B33004EF1BE /* PaiaiUIKit.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 05130F2E21C94B32004EF1BE /* PaiaiUIKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
               | 
            |
| 28 | 27 | 
                 		05130F5721C94C12004EF1BE /* AlertAnimator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 05130F4F21C94C12004EF1BE /* AlertAnimator.swift */; };
               | 
            
| 29 | 28 | 
                 		05130F5921C94C12004EF1BE /* AlertViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 05130F5121C94C12004EF1BE /* AlertViewController.swift */; };
               | 
            
| 30 | 29 | 
                 		05130F5A21C94C12004EF1BE /* PresentDisappearAnimatedTransitioning.swift in Sources */ = {isa = PBXBuildFile; fileRef = 05130F5221C94C12004EF1BE /* PresentDisappearAnimatedTransitioning.swift */; };
               | 
            
                @@ -55,11 +54,10 @@  | 
            ||
| 55 | 54 | 
                 		05130FDA21CA1AE0004EF1BE /* CreateGroupViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A69FFAD01E70047E0006FEE0 /* CreateGroupViewController.swift */; };
               | 
            
| 56 | 55 | 
                 		05130FDB21CA1AE0004EF1BE /* ScanQRViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A69FFAD71E70047E0006FEE0 /* ScanQRViewController.swift */; };
               | 
            
| 57 | 56 | 
                 		05130FDD21CA1B04004EF1BE /* GroupViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A69FFAAB1E7004700006FEE0 /* GroupViewController.swift */; };
               | 
            
| 58 | 
                -		05130FDF21CA1B04004EF1BE /* MemberCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = A69FFAB61E7004700006FEE0 /* MemberCell.swift */; };
               | 
            |
| 57 | 
                +		05130FDF21CA1B04004EF1BE /* GroupMemberCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = A69FFAB61E7004700006FEE0 /* GroupMemberCell.swift */; };
               | 
            |
| 59 | 58 | 
                 		05130FE021CA1B04004EF1BE /* GroupDetailViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A69FFAB11E7004700006FEE0 /* GroupDetailViewController.swift */; };
               | 
            
| 60 | 
                -		05130FE121CA1B04004EF1BE /* GroupMemberController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A69FFAB41E7004700006FEE0 /* GroupMemberController.swift */; };
               | 
            |
| 61 | 
                -		05130FE221CA1B04004EF1BE /* ChangeGroupNameController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A69FFAAE1E7004700006FEE0 /* ChangeGroupNameController.swift */; };
               | 
            |
| 62 | 
                -		05130FE321CA1B04004EF1BE /* ShowGroupQRController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A69FFAB71E7004700006FEE0 /* ShowGroupQRController.swift */; };
               | 
            |
| 59 | 
                +		05130FE121CA1B04004EF1BE /* GroupMemberViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A69FFAB41E7004700006FEE0 /* GroupMemberViewController.swift */; };
               | 
            |
| 60 | 
                +		05130FE221CA1B04004EF1BE /* GroupNameModificationViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A69FFAAE1E7004700006FEE0 /* GroupNameModificationViewController.swift */; };
               | 
            |
| 63 | 61 | 
                 		05130FE421CA1B04004EF1BE /* MessageCommentAndThumbupCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = A69FFADA1E70047E0006FEE0 /* MessageCommentAndThumbupCell.swift */; };
               | 
            
| 64 | 62 | 
                 		05130FE521CA1B04004EF1BE /* MessageSystemCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = A69FFADB1E70047E0006FEE0 /* MessageSystemCell.swift */; };
               | 
            
| 65 | 63 | 
                 		05130FE621CA1B04004EF1BE /* MessageCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 059AA5D921BA1A2000485188 /* MessageCoordinator.swift */; };
               | 
            
                @@ -73,15 +71,11 @@  | 
            ||
| 73 | 71 | 
                 		05130FEF21CA1B04004EF1BE /* MineFeedbackViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A69FFAE41E70047E0006FEE0 /* MineFeedbackViewController.swift */; };
               | 
            
| 74 | 72 | 
                 		05130FF021CA1B04004EF1BE /* MineOrderViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A69FFAEE1E70047E0006FEE0 /* MineOrderViewController.swift */; };
               | 
            
| 75 | 73 | 
                 		05130FF121CA1B04004EF1BE /* MineAboutViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A69FFAE21E70047E0006FEE0 /* MineAboutViewController.swift */; };
               | 
            
| 76 | 
                -		05130FF321CA1B04004EF1BE /* DetailPageHeadCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = A69FFAA01E7004700006FEE0 /* DetailPageHeadCell.swift */; };
               | 
            |
| 77 | 
                -		05130FF421CA1B04004EF1BE /* DetailPagePhotoCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = A69FFAA21E7004700006FEE0 /* DetailPagePhotoCell.swift */; };
               | 
            |
| 78 | 
                -		05130FF521CA1B04004EF1BE /* DetailPageNameCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = A69FFAA11E7004700006FEE0 /* DetailPageNameCell.swift */; };
               | 
            |
| 79 | 
                -		05130FF621CA1B04004EF1BE /* DetailZanImagesCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = A69FFAA51E7004700006FEE0 /* DetailZanImagesCell.swift */; };
               | 
            |
| 80 | 
                -		05130FF721CA1B04004EF1BE /* DetailCommentCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = A69FFA9E1E7004700006FEE0 /* DetailCommentCell.swift */; };
               | 
            |
| 74 | 
                +		05130FF721CA1B04004EF1BE /* PhotoDetailCommentCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = A69FFA9E1E7004700006FEE0 /* PhotoDetailCommentCell.swift */; };
               | 
            |
| 81 | 75 | 
                 		05130FF821CA1B04004EF1BE /* ImageCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = A69FFAA61E7004700006FEE0 /* ImageCell.swift */; };
               | 
            
| 82 | 
                -		05130FF921CA1B04004EF1BE /* DetailPageController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A69FFAA31E7004700006FEE0 /* DetailPageController.swift */; };
               | 
            |
| 76 | 
                +		05130FF921CA1B04004EF1BE /* PhotoDetailViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A69FFAA31E7004700006FEE0 /* PhotoDetailViewController.swift */; };
               | 
            |
| 83 | 77 | 
                 		05130FFB21CA1B04004EF1BE /* ShareController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A69FFAA81E7004700006FEE0 /* ShareController.swift */; };
               | 
            
| 84 | 
                -		05130FFC21CA1B04004EF1BE /* ShowFullPicController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A69FFAA91E7004700006FEE0 /* ShowFullPicController.swift */; };
               | 
            |
| 78 | 
                +		05130FFC21CA1B04004EF1BE /* PhotoPreviewViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A69FFAA91E7004700006FEE0 /* PhotoPreviewViewController.swift */; };
               | 
            |
| 85 | 79 | 
                 		05130FFD21CA1B39004EF1BE /* HardwareAuthorization.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42FECF071EE0339500D4C695 /* HardwareAuthorization.swift */; };
               | 
            
| 86 | 80 | 
                 		05130FFE21CA1B39004EF1BE /* WaterfallFlowLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 050F5D0F1FB9399E00A053D0 /* WaterfallFlowLayout.swift */; };
               | 
            
| 87 | 81 | 
                 		05130FFF21CA1B39004EF1BE /* WaterfallFlowConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 050F5D111FB93A5C00A053D0 /* WaterfallFlowConfiguration.swift */; };
               | 
            
                @@ -104,16 +98,12 @@  | 
            ||
| 104 | 98 | 
                 		0513102621CA1B67004EF1BE /* Resource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0505B34B1F7E4024009E4ED2 /* Resource.swift */; };
               | 
            
| 105 | 99 | 
                 		0513102821CA1B67004EF1BE /* NetWorkCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = A69FFA811E7002B50006FEE0 /* NetWorkCache.swift */; };
               | 
            
| 106 | 100 | 
                 		0513102921CA1B67004EF1BE /* Result.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0594845921B66DA500074EFC /* Result.swift */; };
               | 
            
| 107 | 
                -		0513102B21CA1B67004EF1BE /* HomePhotoRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = A69FFAD61E70047E0006FEE0 /* HomePhotoRepository.swift */; };
               | 
            |
| 101 | 
                +		0513102B21CA1B67004EF1BE /* HomeRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = A69FFAD61E70047E0006FEE0 /* HomeRepository.swift */; };
               | 
            |
| 108 | 102 | 
                 		0513102C21CA1B67004EF1BE /* OrderRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = A69FFAED1E70047E0006FEE0 /* OrderRepository.swift */; };
               | 
            
| 109 | 103 | 
                 		0513102D21CA1B67004EF1BE /* GroupPhotoRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0540C8B01F8C9A640044FCC5 /* GroupPhotoRepository.swift */; };
               | 
            
| 110 | 104 | 
                 		0513102E21CA1B67004EF1BE /* PhotoGroupRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = A69FFAE61E70047E0006FEE0 /* PhotoGroupRepository.swift */; };
               | 
            
| 111 | 
                -		0513102F21CA1B67004EF1BE /* GroupDetailModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A69FFAB01E7004700006FEE0 /* GroupDetailModel.swift */; };
               | 
            |
| 112 | 
                -		0513103021CA1B67004EF1BE /* MessageListRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = A69FFADC1E70047E0006FEE0 /* MessageListRepository.swift */; };
               | 
            |
| 113 | 105 | 
                 		0513103121CA1B67004EF1BE /* MessageRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 059AA62821BA855000485188 /* MessageRepository.swift */; };
               | 
            
| 114 | 
                -		0513103221CA1B67004EF1BE /* DetailModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A69FFA9F1E7004700006FEE0 /* DetailModel.swift */; };
               | 
            |
| 115 | 106 | 
                 		0513103321CA1B67004EF1BE /* UserInfoRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = A69FFA841E7002B50006FEE0 /* UserInfoRepository.swift */; };
               | 
            
| 116 | 
                -		0513103421CA1B67004EF1BE /* PhotoLocalStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 420FDBEA1EA70A9600958CBD /* PhotoLocalStorage.swift */; };
               | 
            |
| 117 | 107 | 
                 		0513103521CA1B67004EF1BE /* RecentGroupInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = A69FFB081E700B700006FEE0 /* RecentGroupInfo.swift */; };
               | 
            
| 118 | 108 | 
                 		0513103921CA1B67004EF1BE /* HomeViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A69FFAD51E70047E0006FEE0 /* HomeViewModel.swift */; };
               | 
            
| 119 | 109 | 
                 		0513103A21CA1B67004EF1BE /* GroupViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A69FFAAC1E7004700006FEE0 /* GroupViewModel.swift */; };
               | 
            
                @@ -121,10 +111,10 @@  | 
            ||
| 121 | 111 | 
                 		0513103C21CA1B67004EF1BE /* GroupMemberViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42CF50491EC0536000D23E9F /* GroupMemberViewModel.swift */; };
               | 
            
| 122 | 112 | 
                 		0513103D21CA1B67004EF1BE /* MineGroupViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42CF50451EC0526C00D23E9F /* MineGroupViewModel.swift */; };
               | 
            
| 123 | 113 | 
                 		0513103E21CA1B67004EF1BE /* MineOrderViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42CF50471EC052B200D23E9F /* MineOrderViewModel.swift */; };
               | 
            
| 124 | 
                -		0513103F21CA1B67004EF1BE /* DetailPageViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A69FFAA41E7004700006FEE0 /* DetailPageViewModel.swift */; };
               | 
            |
| 114 | 
                +		0513103F21CA1B67004EF1BE /* PhotoDetailViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A69FFAA41E7004700006FEE0 /* PhotoDetailViewModel.swift */; };
               | 
            |
| 125 | 115 | 
                 		0513104021CA1B67004EF1BE /* MessageListViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A69FFADE1E70047E0006FEE0 /* MessageListViewModel.swift */; };
               | 
            
| 126 | 116 | 
                 		0513104121CA1B67004EF1BE /* MessageViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 059AA62A21BA85B000485188 /* MessageViewModel.swift */; };
               | 
            
| 127 | 
                -		0513104221CA1B67004EF1BE /* CreateGroupConfirmViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 05A0E8A821C782D700EAB9A2 /* CreateGroupConfirmViewModel.swift */; };
               | 
            |
| 117 | 
                +		0513104221CA1B67004EF1BE /* CreateGroupViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 05A0E8A821C782D700EAB9A2 /* CreateGroupViewModel.swift */; };
               | 
            |
| 128 | 118 | 
                 		0513104321CA1B67004EF1BE /* ScanQRViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 05130F2721C88D35004EF1BE /* ScanQRViewModel.swift */; };
               | 
            
| 129 | 119 | 
                 		0513104521CA1BAD004EF1BE /* ObjectMapper.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 05130FC921CA1997004EF1BE /* ObjectMapper.framework */; };
               | 
            
| 130 | 120 | 
                 		0513104821CA1BAD004EF1BE /* RxCocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 05130FC221CA1997004EF1BE /* RxCocoa.framework */; };
               | 
            
                @@ -138,7 +128,7 @@  | 
            ||
| 138 | 128 | 
                 		0513105921CA1D50004EF1BE /* GroupDetail.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = A69FFB8A1E7018CC0006FEE0 /* GroupDetail.storyboard */; };
               | 
            
| 139 | 129 | 
                 		0513105A21CA1D50004EF1BE /* Message.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = A69FFB901E7018CC0006FEE0 /* Message.storyboard */; };
               | 
            
| 140 | 130 | 
                 		0513105B21CA1D50004EF1BE /* Mine.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = A69FFB921E7018CC0006FEE0 /* Mine.storyboard */; };
               | 
            
| 141 | 
                -		0513105C21CA1D50004EF1BE /* Detail.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = A69FFB881E7018CC0006FEE0 /* Detail.storyboard */; };
               | 
            |
| 131 | 
                +		0513105C21CA1D50004EF1BE /* PhotoDetail.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = A69FFB881E7018CC0006FEE0 /* PhotoDetail.storyboard */; };
               | 
            |
| 142 | 132 | 
                 		0513105D21CA1D95004EF1BE /* PaiaiDataKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 05130F6A21C95373004EF1BE /* PaiaiDataKit.framework */; };
               | 
            
| 143 | 133 | 
                 		0513105E21CA1D95004EF1BE /* PaiaiUIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 05130F2E21C94B32004EF1BE /* PaiaiUIKit.framework */; };
               | 
            
| 144 | 134 | 
                 		0513106021CA1E53004EF1BE /* UIStoryboardExt.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0513105F21CA1E53004EF1BE /* UIStoryboardExt.swift */; };
               | 
            
                @@ -176,11 +166,10 @@  | 
            ||
| 176 | 166 | 
                 		051310B621CB675A004EF1BE /* UIImageView+Kingfisher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0543276621C68C3300C6388D /* UIImageView+Kingfisher.swift */; };
               | 
            
| 177 | 167 | 
                 		051310B821CB6958004EF1BE /* UserInfoStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 051310B721CB6958004EF1BE /* UserInfoStore.swift */; };
               | 
            
| 178 | 168 | 
                 		051310C021CB6EF4004EF1BE /* UserInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 051310BF21CB6EF4004EF1BE /* UserInfo.swift */; };
               | 
            
| 179 | 
                -		0521144621EF38B60047C55A /* PaiaiDataKitTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0521144521EF38B60047C55A /* PaiaiDataKitTests.swift */; };
               | 
            |
| 180 | 
                -		0521144821EF38B60047C55A /* PaiaiDataKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 05130F6A21C95373004EF1BE /* PaiaiDataKit.framework */; };
               | 
            |
| 181 | 169 | 
                 		0521145421F083F20047C55A /* ToastView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0521145321F083F20047C55A /* ToastView.swift */; };
               | 
            
| 182 | 170 | 
                 		052BF1C821E344020010D270 /* PullToRefresh.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 052BF1C721E344020010D270 /* PullToRefresh.framework */; };
               | 
            
| 183 | 171 | 
                 		052BF1C921E344280010D270 /* PullToRefresh.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 052BF1C721E344020010D270 /* PullToRefresh.framework */; };
               | 
            
| 172 | 
                +		0530951B221AB3EC00408D34 /* GroupDetailMemeberView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0530951A221AB3EC00408D34 /* GroupDetailMemeberView.swift */; };
               | 
            |
| 184 | 173 | 
                 		0535D6D921D32A89008D9403 /* WXUserInfoRemoteAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0535D6D821D32A89008D9403 /* WXUserInfoRemoteAPI.swift */; };
               | 
            
| 185 | 174 | 
                 		0535D6DB21D32A9E008D9403 /* GuestUserInfoRemoteAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0535D6DA21D32A9E008D9403 /* GuestUserInfoRemoteAPI.swift */; };
               | 
            
| 186 | 175 | 
                 		053E126521F1718E00A64893 /* PageOption.swift in Sources */ = {isa = PBXBuildFile; fileRef = 053E126421F1718E00A64893 /* PageOption.swift */; };
               | 
            
                @@ -196,6 +185,13 @@  | 
            ||
| 196 | 185 | 
                 		0543E80B21D1DF4000A42807 /* GroupMemberItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0543E80A21D1DF4000A42807 /* GroupMemberItem.swift */; };
               | 
            
| 197 | 186 | 
                 		0543E80D21D1E2EA00A42807 /* PhotoGroupDetailRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0543E80C21D1E2EA00A42807 /* PhotoGroupDetailRepository.swift */; };
               | 
            
| 198 | 187 | 
                 		0543E80F21D1FD1100A42807 /* GroupDetailItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0543E80E21D1FD1100A42807 /* GroupDetailItem.swift */; };
               | 
            
| 188 | 
                +		0546D9852242460700742939 /* OriginData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0546D9842242460700742939 /* OriginData.swift */; };
               | 
            |
| 189 | 
                +		0546D98E2243782300742939 /* ShareView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0546D98D2243782300742939 /* ShareView.swift */; };
               | 
            |
| 190 | 
                +		054B6C45223F884600939FE6 /* PhotoDetailRemoteAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 054B6C44223F884600939FE6 /* PhotoDetailRemoteAPI.swift */; };
               | 
            |
| 191 | 
                +		054B6C46223F966A00939FE6 /* RxDataSources.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 05130FC421CA1997004EF1BE /* RxDataSources.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
               | 
            |
| 192 | 
                +		05594BFF2240BEDE002D4910 /* PhotoDetailListViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 05594BFE2240BEDE002D4910 /* PhotoDetailListViewModel.swift */; };
               | 
            |
| 193 | 
                +		05594C012240BF9C002D4910 /* PhotoPurchaseViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 05594C002240BF9C002D4910 /* PhotoPurchaseViewModel.swift */; };
               | 
            |
| 194 | 
                +		05594C032240E94E002D4910 /* PhotoDetailImageCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 05594C022240E94E002D4910 /* PhotoDetailImageCell.swift */; };
               | 
            |
| 199 | 195 | 
                 		055BB53E220AEA3B009548AA /* NiblessViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 055BB53D220AEA3B009548AA /* NiblessViewController.swift */; };
               | 
            
| 200 | 196 | 
                 		055BB541220AEA62009548AA /* NiblessView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 055BB540220AEA62009548AA /* NiblessView.swift */; };
               | 
            
| 201 | 197 | 
                 		055EFAD7221A4DB400450AD5 /* GroupQRView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 055EFAD6221A4DB400450AD5 /* GroupQRView.swift */; };
               | 
            
                @@ -216,7 +212,7 @@  | 
            ||
| 216 | 212 | 
                 		057CA9C621DCA2C900FB7D03 /* PhotoRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 057CA9C521DCA2C900FB7D03 /* PhotoRepository.swift */; };
               | 
            
| 217 | 213 | 
                 		057CA9CA21DCA70B00FB7D03 /* GroupRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 057CA9C921DCA70B00FB7D03 /* GroupRepository.swift */; };
               | 
            
| 218 | 214 | 
                 		057CA9CE21DDAE8100FB7D03 /* GroupDetailRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 057CA9CD21DDAE8100FB7D03 /* GroupDetailRepository.swift */; };
               | 
            
| 219 | 
                -		057CA9D021DDB7DD00FB7D03 /* NetWorkData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 057CA9CF21DDB7DD00FB7D03 /* NetWorkData.swift */; };
               | 
            |
| 215 | 
                +		057CA9D021DDB7DD00FB7D03 /* NetworkArrayData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 057CA9CF21DDB7DD00FB7D03 /* NetworkArrayData.swift */; };
               | 
            |
| 220 | 216 | 
                 		0584FD7521F9C70D00FA1E3E /* SideAnimator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0584FD7421F9C70D00FA1E3E /* SideAnimator.swift */; };
               | 
            
| 221 | 217 | 
                 		0584FD7721F9C8A300FA1E3E /* PresentAnimatorDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0584FD7621F9C8A300FA1E3E /* PresentAnimatorDelegate.swift */; };
               | 
            
| 222 | 218 | 
                 		0584FD7C21FABC1400FA1E3E /* PresentExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0584FD7B21FABC1400FA1E3E /* PresentExtension.swift */; };
               | 
            
                @@ -225,11 +221,10 @@  | 
            ||
| 225 | 221 | 
                 		059B58A621F7235D00FA64C2 /* AlertAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 059B58A521F7235D00FA64C2 /* AlertAction.swift */; };
               | 
            
| 226 | 222 | 
                 		059B58A821F83B1600FA64C2 /* CenterCancelItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 059B58A721F83B1600FA64C2 /* CenterCancelItem.swift */; };
               | 
            
| 227 | 223 | 
                 		059B58AA21F83B2E00FA64C2 /* CenterConfirmItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 059B58A921F83B2E00FA64C2 /* CenterConfirmItem.swift */; };
               | 
            
| 228 | 
                -		05B2C5EF21D48133008063B3 /* HomePhotoRemoteAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 05B2C5EE21D48133008063B3 /* HomePhotoRemoteAPI.swift */; };
               | 
            |
| 224 | 
                +		05B2C5EF21D48133008063B3 /* HomeRemoteAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 05B2C5EE21D48133008063B3 /* HomeRemoteAPI.swift */; };
               | 
            |
| 229 | 225 | 
                 		05B2C60621D60E97008063B3 /* DictionaryExt.swift in Sources */ = {isa = PBXBuildFile; fileRef = 05B2C60521D60E97008063B3 /* DictionaryExt.swift */; };
               | 
            
| 230 | 226 | 
                 		05B2C61D21D710C5008063B3 /* GroupRemoteAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 05B2C61C21D710C5008063B3 /* GroupRemoteAPI.swift */; };
               | 
            
| 231 | 227 | 
                 		05B2C62121D727AA008063B3 /* StatusResource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 05B2C62021D727AA008063B3 /* StatusResource.swift */; };
               | 
            
| 232 | 
                -		05B2C62321D72EAF008063B3 /* MessageListRemoteAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 05B2C62221D72EAF008063B3 /* MessageListRemoteAPI.swift */; };
               | 
            |
| 233 | 228 | 
                 		05B2C62721D74E92008063B3 /* OrderRemoteAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 05B2C62621D74E92008063B3 /* OrderRemoteAPI.swift */; };
               | 
            
| 234 | 229 | 
                 		05B2C62921D74F27008063B3 /* MessageRemoteAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 05B2C62821D74F27008063B3 /* MessageRemoteAPI.swift */; };
               | 
            
| 235 | 230 | 
                 		05B2C62B21D750F1008063B3 /* FeedbackRemoteAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 05B2C62A21D750F1008063B3 /* FeedbackRemoteAPI.swift */; };
               | 
            
                @@ -237,8 +232,8 @@  | 
            ||
| 237 | 232 | 
                 		05B2C63121D75A1B008063B3 /* ContentResource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 05B2C63021D75A1B008063B3 /* ContentResource.swift */; };
               | 
            
| 238 | 233 | 
                 		05C0CEF921F8567C00993DE2 /* AlertView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 05C0CEF821F8567C00993DE2 /* AlertView.swift */; };
               | 
            
| 239 | 234 | 
                 		05C0CEFB21F85A7700993DE2 /* ActionSheetController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 05C0CEFA21F85A7700993DE2 /* ActionSheetController.swift */; };
               | 
            
| 240 | 
                -		05C0D98E21D22119000B7B2A /* ThumbupUserItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 05C0D98D21D22119000B7B2A /* ThumbupUserItem.swift */; };
               | 
            |
| 241 | 
                -		05C0D99021D2219A000B7B2A /* CommentItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 05C0D98F21D2219A000B7B2A /* CommentItem.swift */; };
               | 
            |
| 235 | 
                +		05C0D98E21D22119000B7B2A /* PhotoThumbupUserItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 05C0D98D21D22119000B7B2A /* PhotoThumbupUserItem.swift */; };
               | 
            |
| 236 | 
                +		05C0D99021D2219A000B7B2A /* PhotoCommentItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 05C0D98F21D2219A000B7B2A /* PhotoCommentItem.swift */; };
               | 
            |
| 242 | 237 | 
                 		05C0D99621D22AA7000B7B2A /* PhotoDetailRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 05C0D99521D22AA7000B7B2A /* PhotoDetailRepository.swift */; };
               | 
            
| 243 | 238 | 
                 		05C0D9A421D28591000B7B2A /* UserInfoRemoteAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 05C0D9A321D28591000B7B2A /* UserInfoRemoteAPI.swift */; };
               | 
            
| 244 | 239 | 
                 		05C5285621FE98F50090ECB5 /* GestureRecognizerProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 05C5285521FE98F50090ECB5 /* GestureRecognizerProxy.swift */; };
               | 
            
                @@ -300,35 +295,21 @@  | 
            ||
| 300 | 295 | 
                remoteGlobalIDString = 05130F6921C95373004EF1BE;  | 
            
| 301 | 296 | 
                remoteInfo = PaiaiDataKit;  | 
            
| 302 | 297 | 
                };  | 
            
| 303 | 
                -		0521144921EF38B60047C55A /* PBXContainerItemProxy */ = {
               | 
            |
| 304 | 
                - isa = PBXContainerItemProxy;  | 
            |
| 305 | 
                - containerPortal = 6CEBD0F71CA8D680004DBDE0 /* Project object */;  | 
            |
| 306 | 
                - proxyType = 1;  | 
            |
| 307 | 
                - remoteGlobalIDString = 05130F6921C95373004EF1BE;  | 
            |
| 308 | 
                - remoteInfo = PaiaiDataKit;  | 
            |
| 309 | 
                - };  | 
            |
| 310 | 
                -		0521144E21EF3A440047C55A /* PBXContainerItemProxy */ = {
               | 
            |
| 311 | 
                - isa = PBXContainerItemProxy;  | 
            |
| 312 | 
                - containerPortal = 6CEBD0F71CA8D680004DBDE0 /* Project object */;  | 
            |
| 313 | 
                - proxyType = 1;  | 
            |
| 314 | 
                - remoteGlobalIDString = 6CEBD0FE1CA8D680004DBDE0;  | 
            |
| 315 | 
                - remoteInfo = Paiai;  | 
            |
| 316 | 
                - };  | 
            |
| 317 | 298 | 
                /* End PBXContainerItemProxy section */  | 
            
| 318 | 299 | 
                 | 
            
| 319 | 300 | 
                /* Begin PBXCopyFilesBuildPhase section */  | 
            
| 320 | 301 | 
                 		05130F4821C94B33004EF1BE /* Embed Frameworks */ = {
               | 
            
| 321 | 302 | 
                isa = PBXCopyFilesBuildPhase;  | 
            
| 322 | 
                - buildActionMask = 2147483647;  | 
            |
| 303 | 
                + buildActionMask = 8;  | 
            |
| 323 | 304 | 
                dstPath = "";  | 
            
| 324 | 305 | 
                dstSubfolderSpec = 10;  | 
            
| 325 | 306 | 
                files = (  | 
            
| 307 | 
                + 054B6C46223F966A00939FE6 /* RxDataSources.framework in Embed Frameworks */,  | 
            |
| 326 | 308 | 
                05130F8021C95373004EF1BE /* PaiaiDataKit.framework in Embed Frameworks */,  | 
            
| 327 | 309 | 
                05130FA421C9E5E9004EF1BE /* Paiai_iOS.framework in Embed Frameworks */,  | 
            
| 328 | 
                - 05130F4421C94B33004EF1BE /* PaiaiUIKit.framework in Embed Frameworks */,  | 
            |
| 329 | 310 | 
                );  | 
            
| 330 | 311 | 
                name = "Embed Frameworks";  | 
            
| 331 | 
                - runOnlyForDeploymentPostprocessing = 0;  | 
            |
| 312 | 
                + runOnlyForDeploymentPostprocessing = 1;  | 
            |
| 332 | 313 | 
                };  | 
            
| 333 | 314 | 
                /* End PBXCopyFilesBuildPhase section */  | 
            
| 334 | 315 | 
                 | 
            
                @@ -409,11 +390,11 @@  | 
            ||
| 409 | 390 | 
                 		051310B321CB5EC3004EF1BE /* Kingfisher.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Kingfisher.framework; path = Carthage/Build/iOS/Kingfisher.framework; sourceTree = "<group>"; };
               | 
            
| 410 | 391 | 
                 		051310B721CB6958004EF1BE /* UserInfoStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserInfoStore.swift; sourceTree = "<group>"; };
               | 
            
| 411 | 392 | 
                 		051310BF21CB6EF4004EF1BE /* UserInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserInfo.swift; sourceTree = "<group>"; };
               | 
            
| 412 | 
                -		0521144321EF38B60047C55A /* PaiaiDataKitTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = PaiaiDataKitTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
               | 
            |
| 413 | 393 | 
                 		0521144521EF38B60047C55A /* PaiaiDataKitTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PaiaiDataKitTests.swift; sourceTree = "<group>"; };
               | 
            
| 414 | 394 | 
                 		0521144721EF38B60047C55A /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
               | 
            
| 415 | 395 | 
                 		0521145321F083F20047C55A /* ToastView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ToastView.swift; sourceTree = "<group>"; };
               | 
            
| 416 | 396 | 
                 		052BF1C721E344020010D270 /* PullToRefresh.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = PullToRefresh.framework; path = Carthage/Build/iOS/PullToRefresh.framework; sourceTree = "<group>"; };
               | 
            
| 397 | 
                +		0530951A221AB3EC00408D34 /* GroupDetailMemeberView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GroupDetailMemeberView.swift; sourceTree = "<group>"; };
               | 
            |
| 417 | 398 | 
                 		0535D6D821D32A89008D9403 /* WXUserInfoRemoteAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WXUserInfoRemoteAPI.swift; sourceTree = "<group>"; };
               | 
            
| 418 | 399 | 
                 		0535D6DA21D32A9E008D9403 /* GuestUserInfoRemoteAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GuestUserInfoRemoteAPI.swift; sourceTree = "<group>"; };
               | 
            
| 419 | 400 | 
                 		053E126421F1718E00A64893 /* PageOption.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PageOption.swift; sourceTree = "<group>"; };
               | 
            
                @@ -446,8 +427,14 @@  | 
            ||
| 446 | 427 | 
                 		0543E80C21D1E2EA00A42807 /* PhotoGroupDetailRepository.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhotoGroupDetailRepository.swift; sourceTree = "<group>"; };
               | 
            
| 447 | 428 | 
                 		0543E80E21D1FD1100A42807 /* GroupDetailItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GroupDetailItem.swift; sourceTree = "<group>"; };
               | 
            
| 448 | 429 | 
                 		05468AF11F8B73A000B8F469 /* PhotoItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhotoItem.swift; sourceTree = "<group>"; };
               | 
            
| 430 | 
                +		0546D9842242460700742939 /* OriginData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OriginData.swift; sourceTree = "<group>"; };
               | 
            |
| 431 | 
                +		0546D98D2243782300742939 /* ShareView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareView.swift; sourceTree = "<group>"; };
               | 
            |
| 449 | 432 | 
                 		054863661FA326CB00A39DA0 /* PhotoCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PhotoCell.swift; sourceTree = "<group>"; };
               | 
            
| 450 | 433 | 
                 		054863671FA326CB00A39DA0 /* PhotoCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = PhotoCell.xib; sourceTree = "<group>"; };
               | 
            
| 434 | 
                +		054B6C44223F884600939FE6 /* PhotoDetailRemoteAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhotoDetailRemoteAPI.swift; sourceTree = "<group>"; };
               | 
            |
| 435 | 
                +		05594BFE2240BEDE002D4910 /* PhotoDetailListViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhotoDetailListViewModel.swift; sourceTree = "<group>"; };
               | 
            |
| 436 | 
                +		05594C002240BF9C002D4910 /* PhotoPurchaseViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhotoPurchaseViewModel.swift; sourceTree = "<group>"; };
               | 
            |
| 437 | 
                +		05594C022240E94E002D4910 /* PhotoDetailImageCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhotoDetailImageCell.swift; sourceTree = "<group>"; };
               | 
            |
| 451 | 438 | 
                 		055BB53D220AEA3B009548AA /* NiblessViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NiblessViewController.swift; sourceTree = "<group>"; };
               | 
            
| 452 | 439 | 
                 		055BB540220AEA62009548AA /* NiblessView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NiblessView.swift; sourceTree = "<group>"; };
               | 
            
| 453 | 440 | 
                 		055EFAD6221A4DB400450AD5 /* GroupQRView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GroupQRView.swift; sourceTree = "<group>"; };
               | 
            
                @@ -467,7 +454,7 @@  | 
            ||
| 467 | 454 | 
                 		057CA9C521DCA2C900FB7D03 /* PhotoRepository.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhotoRepository.swift; sourceTree = "<group>"; };
               | 
            
| 468 | 455 | 
                 		057CA9C921DCA70B00FB7D03 /* GroupRepository.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GroupRepository.swift; sourceTree = "<group>"; };
               | 
            
| 469 | 456 | 
                 		057CA9CD21DDAE8100FB7D03 /* GroupDetailRepository.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GroupDetailRepository.swift; sourceTree = "<group>"; };
               | 
            
| 470 | 
                -		057CA9CF21DDB7DD00FB7D03 /* NetWorkData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetWorkData.swift; sourceTree = "<group>"; };
               | 
            |
| 457 | 
                +		057CA9CF21DDB7DD00FB7D03 /* NetworkArrayData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkArrayData.swift; sourceTree = "<group>"; };
               | 
            |
| 471 | 458 | 
                 		0584FD7421F9C70D00FA1E3E /* SideAnimator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SideAnimator.swift; sourceTree = "<group>"; };
               | 
            
| 472 | 459 | 
                 		0584FD7621F9C8A300FA1E3E /* PresentAnimatorDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PresentAnimatorDelegate.swift; sourceTree = "<group>"; };
               | 
            
| 473 | 460 | 
                 		0584FD7B21FABC1400FA1E3E /* PresentExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PresentExtension.swift; sourceTree = "<group>"; };
               | 
            
                @@ -481,12 +468,11 @@  | 
            ||
| 481 | 468 | 
                 		059B58A521F7235D00FA64C2 /* AlertAction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlertAction.swift; sourceTree = "<group>"; };
               | 
            
| 482 | 469 | 
                 		059B58A721F83B1600FA64C2 /* CenterCancelItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CenterCancelItem.swift; sourceTree = "<group>"; };
               | 
            
| 483 | 470 | 
                 		059B58A921F83B2E00FA64C2 /* CenterConfirmItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CenterConfirmItem.swift; sourceTree = "<group>"; };
               | 
            
| 484 | 
                -		05A0E8A821C782D700EAB9A2 /* CreateGroupConfirmViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreateGroupConfirmViewModel.swift; sourceTree = "<group>"; };
               | 
            |
| 485 | 
                -		05B2C5EE21D48133008063B3 /* HomePhotoRemoteAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomePhotoRemoteAPI.swift; sourceTree = "<group>"; };
               | 
            |
| 471 | 
                +		05A0E8A821C782D700EAB9A2 /* CreateGroupViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreateGroupViewModel.swift; sourceTree = "<group>"; };
               | 
            |
| 472 | 
                +		05B2C5EE21D48133008063B3 /* HomeRemoteAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeRemoteAPI.swift; sourceTree = "<group>"; };
               | 
            |
| 486 | 473 | 
                 		05B2C60521D60E97008063B3 /* DictionaryExt.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DictionaryExt.swift; sourceTree = "<group>"; };
               | 
            
| 487 | 474 | 
                 		05B2C61C21D710C5008063B3 /* GroupRemoteAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GroupRemoteAPI.swift; sourceTree = "<group>"; };
               | 
            
| 488 | 475 | 
                 		05B2C62021D727AA008063B3 /* StatusResource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusResource.swift; sourceTree = "<group>"; };
               | 
            
| 489 | 
                -		05B2C62221D72EAF008063B3 /* MessageListRemoteAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageListRemoteAPI.swift; sourceTree = "<group>"; };
               | 
            |
| 490 | 476 | 
                 		05B2C62621D74E92008063B3 /* OrderRemoteAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OrderRemoteAPI.swift; sourceTree = "<group>"; };
               | 
            
| 491 | 477 | 
                 		05B2C62821D74F27008063B3 /* MessageRemoteAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageRemoteAPI.swift; sourceTree = "<group>"; };
               | 
            
| 492 | 478 | 
                 		05B2C62A21D750F1008063B3 /* FeedbackRemoteAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedbackRemoteAPI.swift; sourceTree = "<group>"; };
               | 
            
                @@ -494,8 +480,8 @@  | 
            ||
| 494 | 480 | 
                 		05B2C63021D75A1B008063B3 /* ContentResource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentResource.swift; sourceTree = "<group>"; };
               | 
            
| 495 | 481 | 
                 		05C0CEF821F8567C00993DE2 /* AlertView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlertView.swift; sourceTree = "<group>"; };
               | 
            
| 496 | 482 | 
                 		05C0CEFA21F85A7700993DE2 /* ActionSheetController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionSheetController.swift; sourceTree = "<group>"; };
               | 
            
| 497 | 
                -		05C0D98D21D22119000B7B2A /* ThumbupUserItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThumbupUserItem.swift; sourceTree = "<group>"; };
               | 
            |
| 498 | 
                -		05C0D98F21D2219A000B7B2A /* CommentItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CommentItem.swift; sourceTree = "<group>"; };
               | 
            |
| 483 | 
                +		05C0D98D21D22119000B7B2A /* PhotoThumbupUserItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhotoThumbupUserItem.swift; sourceTree = "<group>"; };
               | 
            |
| 484 | 
                +		05C0D98F21D2219A000B7B2A /* PhotoCommentItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhotoCommentItem.swift; sourceTree = "<group>"; };
               | 
            |
| 499 | 485 | 
                 		05C0D99521D22AA7000B7B2A /* PhotoDetailRepository.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhotoDetailRepository.swift; sourceTree = "<group>"; };
               | 
            
| 500 | 486 | 
                 		05C0D9A321D28591000B7B2A /* UserInfoRemoteAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserInfoRemoteAPI.swift; sourceTree = "<group>"; };
               | 
            
| 501 | 487 | 
                 		05C5285521FE98F50090ECB5 /* GestureRecognizerProxy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GestureRecognizerProxy.swift; sourceTree = "<group>"; };
               | 
            
                @@ -520,7 +506,6 @@  | 
            ||
| 520 | 506 | 
                 		05D3A3CF2200288400A29A20 /* Storyboarded.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Storyboarded.swift; sourceTree = "<group>"; };
               | 
            
| 521 | 507 | 
                 		05E80E2F21DF65D4006368C4 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
               | 
            
| 522 | 508 | 
                 		3864C06C1CAD27EC0048ADAD /* Swift-bridge.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Swift-bridge.h"; sourceTree = "<group>"; };
               | 
            
| 523 | 
                -		420FDBEA1EA70A9600958CBD /* PhotoLocalStorage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PhotoLocalStorage.swift; sourceTree = "<group>"; };
               | 
            |
| 524 | 509 | 
                 		42CF50451EC0526C00D23E9F /* MineGroupViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MineGroupViewModel.swift; sourceTree = "<group>"; };
               | 
            
| 525 | 510 | 
                 		42CF50471EC052B200D23E9F /* MineOrderViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MineOrderViewModel.swift; sourceTree = "<group>"; };
               | 
            
| 526 | 511 | 
                 		42CF50491EC0536000D23E9F /* GroupMemberViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GroupMemberViewModel.swift; sourceTree = "<group>"; };
               | 
            
                @@ -531,35 +516,27 @@  | 
            ||
| 531 | 516 | 
                 		A69FFA791E7002970006FEE0 /* LoginViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoginViewController.swift; sourceTree = "<group>"; };
               | 
            
| 532 | 517 | 
                 		A69FFA811E7002B50006FEE0 /* NetWorkCache.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NetWorkCache.swift; sourceTree = "<group>"; };
               | 
            
| 533 | 518 | 
                 		A69FFA841E7002B50006FEE0 /* UserInfoRepository.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UserInfoRepository.swift; sourceTree = "<group>"; };
               | 
            
| 534 | 
                -		A69FFA9E1E7004700006FEE0 /* DetailCommentCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DetailCommentCell.swift; sourceTree = "<group>"; };
               | 
            |
| 535 | 
                -		A69FFA9F1E7004700006FEE0 /* DetailModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DetailModel.swift; sourceTree = "<group>"; };
               | 
            |
| 536 | 
                -		A69FFAA01E7004700006FEE0 /* DetailPageHeadCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DetailPageHeadCell.swift; sourceTree = "<group>"; };
               | 
            |
| 537 | 
                -		A69FFAA11E7004700006FEE0 /* DetailPageNameCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DetailPageNameCell.swift; sourceTree = "<group>"; };
               | 
            |
| 538 | 
                -		A69FFAA21E7004700006FEE0 /* DetailPagePhotoCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DetailPagePhotoCell.swift; sourceTree = "<group>"; };
               | 
            |
| 539 | 
                -		A69FFAA31E7004700006FEE0 /* DetailPageController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DetailPageController.swift; sourceTree = "<group>"; };
               | 
            |
| 540 | 
                -		A69FFAA41E7004700006FEE0 /* DetailPageViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DetailPageViewModel.swift; sourceTree = "<group>"; };
               | 
            |
| 541 | 
                -		A69FFAA51E7004700006FEE0 /* DetailZanImagesCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DetailZanImagesCell.swift; sourceTree = "<group>"; };
               | 
            |
| 519 | 
                +		A69FFA9E1E7004700006FEE0 /* PhotoDetailCommentCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PhotoDetailCommentCell.swift; sourceTree = "<group>"; };
               | 
            |
| 520 | 
                +		A69FFAA31E7004700006FEE0 /* PhotoDetailViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PhotoDetailViewController.swift; sourceTree = "<group>"; };
               | 
            |
| 521 | 
                +		A69FFAA41E7004700006FEE0 /* PhotoDetailViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PhotoDetailViewModel.swift; sourceTree = "<group>"; };
               | 
            |
| 542 | 522 | 
                 		A69FFAA61E7004700006FEE0 /* ImageCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImageCell.swift; sourceTree = "<group>"; wrapsLines = 0; };
               | 
            
| 543 | 523 | 
                 		A69FFAA81E7004700006FEE0 /* ShareController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ShareController.swift; sourceTree = "<group>"; };
               | 
            
| 544 | 
                -		A69FFAA91E7004700006FEE0 /* ShowFullPicController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ShowFullPicController.swift; sourceTree = "<group>"; };
               | 
            |
| 524 | 
                +		A69FFAA91E7004700006FEE0 /* PhotoPreviewViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PhotoPreviewViewController.swift; sourceTree = "<group>"; };
               | 
            |
| 545 | 525 | 
                 		A69FFAAB1E7004700006FEE0 /* GroupViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GroupViewController.swift; sourceTree = "<group>"; };
               | 
            
| 546 | 526 | 
                 		A69FFAAC1E7004700006FEE0 /* GroupViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GroupViewModel.swift; sourceTree = "<group>"; };
               | 
            
| 547 | 
                -		A69FFAAE1E7004700006FEE0 /* ChangeGroupNameController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChangeGroupNameController.swift; sourceTree = "<group>"; };
               | 
            |
| 548 | 
                -		A69FFAB01E7004700006FEE0 /* GroupDetailModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GroupDetailModel.swift; sourceTree = "<group>"; };
               | 
            |
| 527 | 
                +		A69FFAAE1E7004700006FEE0 /* GroupNameModificationViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GroupNameModificationViewController.swift; sourceTree = "<group>"; };
               | 
            |
| 549 | 528 | 
                 		A69FFAB11E7004700006FEE0 /* GroupDetailViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GroupDetailViewController.swift; sourceTree = "<group>"; };
               | 
            
| 550 | 529 | 
                 		A69FFAB21E7004700006FEE0 /* GroupDetailViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GroupDetailViewModel.swift; sourceTree = "<group>"; };
               | 
            
| 551 | 
                -		A69FFAB41E7004700006FEE0 /* GroupMemberController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GroupMemberController.swift; sourceTree = "<group>"; };
               | 
            |
| 552 | 
                -		A69FFAB61E7004700006FEE0 /* MemberCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MemberCell.swift; sourceTree = "<group>"; };
               | 
            |
| 553 | 
                -		A69FFAB71E7004700006FEE0 /* ShowGroupQRController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ShowGroupQRController.swift; sourceTree = "<group>"; };
               | 
            |
| 530 | 
                +		A69FFAB41E7004700006FEE0 /* GroupMemberViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GroupMemberViewController.swift; sourceTree = "<group>"; };
               | 
            |
| 531 | 
                +		A69FFAB61E7004700006FEE0 /* GroupMemberCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GroupMemberCell.swift; sourceTree = "<group>"; };
               | 
            |
| 554 | 532 | 
                 		A69FFACF1E70047E0006FEE0 /* CreateGroupConfirmViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CreateGroupConfirmViewController.swift; sourceTree = "<group>"; };
               | 
            
| 555 | 533 | 
                 		A69FFAD01E70047E0006FEE0 /* CreateGroupViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CreateGroupViewController.swift; sourceTree = "<group>"; };
               | 
            
| 556 | 534 | 
                 		A69FFAD41E70047E0006FEE0 /* HomeViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HomeViewController.swift; sourceTree = "<group>"; wrapsLines = 1; };
               | 
            
| 557 | 535 | 
                 		A69FFAD51E70047E0006FEE0 /* HomeViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HomeViewModel.swift; sourceTree = "<group>"; wrapsLines = 1; };
               | 
            
| 558 | 
                -		A69FFAD61E70047E0006FEE0 /* HomePhotoRepository.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HomePhotoRepository.swift; sourceTree = "<group>"; };
               | 
            |
| 536 | 
                +		A69FFAD61E70047E0006FEE0 /* HomeRepository.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HomeRepository.swift; sourceTree = "<group>"; };
               | 
            |
| 559 | 537 | 
                 		A69FFAD71E70047E0006FEE0 /* ScanQRViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ScanQRViewController.swift; sourceTree = "<group>"; };
               | 
            
| 560 | 538 | 
                 		A69FFADA1E70047E0006FEE0 /* MessageCommentAndThumbupCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageCommentAndThumbupCell.swift; sourceTree = "<group>"; };
               | 
            
| 561 | 539 | 
                 		A69FFADB1E70047E0006FEE0 /* MessageSystemCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageSystemCell.swift; sourceTree = "<group>"; };
               | 
            
| 562 | 
                -		A69FFADC1E70047E0006FEE0 /* MessageListRepository.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageListRepository.swift; sourceTree = "<group>"; };
               | 
            |
| 563 | 540 | 
                 		A69FFADD1E70047E0006FEE0 /* MessageListViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageListViewController.swift; sourceTree = "<group>"; };
               | 
            
| 564 | 541 | 
                 		A69FFADE1E70047E0006FEE0 /* MessageListViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageListViewModel.swift; sourceTree = "<group>"; };
               | 
            
| 565 | 542 | 
                 		A69FFAE21E70047E0006FEE0 /* MineAboutViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MineAboutViewController.swift; sourceTree = "<group>"; };
               | 
            
                @@ -571,7 +548,7 @@  | 
            ||
| 571 | 548 | 
                 		A69FFAED1E70047E0006FEE0 /* OrderRepository.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OrderRepository.swift; sourceTree = "<group>"; };
               | 
            
| 572 | 549 | 
                 		A69FFAEE1E70047E0006FEE0 /* MineOrderViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MineOrderViewController.swift; sourceTree = "<group>"; };
               | 
            
| 573 | 550 | 
                 		A69FFB081E700B700006FEE0 /* RecentGroupInfo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RecentGroupInfo.swift; sourceTree = "<group>"; };
               | 
            
| 574 | 
                -		A69FFB891E7018CC0006FEE0 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Detail.storyboard; sourceTree = "<group>"; };
               | 
            |
| 551 | 
                +		A69FFB891E7018CC0006FEE0 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = PhotoDetail.storyboard; sourceTree = "<group>"; };
               | 
            |
| 575 | 552 | 
                 		A69FFB8B1E7018CC0006FEE0 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = GroupDetail.storyboard; sourceTree = "<group>"; };
               | 
            
| 576 | 553 | 
                 		A69FFB8D1E7018CC0006FEE0 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = LaunchScreen.storyboard; sourceTree = "<group>"; };
               | 
            
| 577 | 554 | 
                 		A69FFB8F1E7018CC0006FEE0 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Main.storyboard; sourceTree = "<group>"; };
               | 
            
                @@ -623,14 +600,6 @@  | 
            ||
| 623 | 600 | 
                );  | 
            
| 624 | 601 | 
                runOnlyForDeploymentPostprocessing = 0;  | 
            
| 625 | 602 | 
                };  | 
            
| 626 | 
                -		0521144021EF38B60047C55A /* Frameworks */ = {
               | 
            |
| 627 | 
                - isa = PBXFrameworksBuildPhase;  | 
            |
| 628 | 
                - buildActionMask = 2147483647;  | 
            |
| 629 | 
                - files = (  | 
            |
| 630 | 
                - 0521144821EF38B60047C55A /* PaiaiDataKit.framework in Frameworks */,  | 
            |
| 631 | 
                - );  | 
            |
| 632 | 
                - runOnlyForDeploymentPostprocessing = 0;  | 
            |
| 633 | 
                - };  | 
            |
| 634 | 603 | 
                 		6CEBD0FC1CA8D680004DBDE0 /* Frameworks */ = {
               | 
            
| 635 | 604 | 
                isa = PBXFrameworksBuildPhase;  | 
            
| 636 | 605 | 
                buildActionMask = 2147483647;  | 
            
                @@ -786,19 +755,16 @@  | 
            ||
| 786 | 755 | 
                isa = PBXGroup;  | 
            
| 787 | 756 | 
                children = (  | 
            
| 788 | 757 | 
                05C71C0721DDBD55003E7CEE /* JSONCode.swift */,  | 
            
| 789 | 
                - 057CA9CF21DDB7DD00FB7D03 /* NetWorkData.swift */,  | 
            |
| 758 | 
                + 051310BF21CB6EF4004EF1BE /* UserInfo.swift */,  | 
            |
| 790 | 759 | 
                05468AF11F8B73A000B8F469 /* PhotoItem.swift */,  | 
            
| 791 | 760 | 
                05130FAF21C9E6CD004EF1BE /* OrderItem.swift */,  | 
            
| 792 | 761 | 
                05130FB221C9E76A004EF1BE /* GroupItem.swift */,  | 
            
| 793 | 762 | 
                05130FB421C9E7CE004EF1BE /* MessageItem.swift */,  | 
            
| 794 | 763 | 
                05130FB621C9E80F004EF1BE /* MessageListItem.swift */,  | 
            
| 795 | 
                - 051310BF21CB6EF4004EF1BE /* UserInfo.swift */,  | 
            |
| 796 | 
                - A69FFAB01E7004700006FEE0 /* GroupDetailModel.swift */,  | 
            |
| 797 | 
                - 0543E80A21D1DF4000A42807 /* GroupMemberItem.swift */,  | 
            |
| 798 | 764 | 
                0543E80E21D1FD1100A42807 /* GroupDetailItem.swift */,  | 
            
| 799 | 
                - A69FFA9F1E7004700006FEE0 /* DetailModel.swift */,  | 
            |
| 800 | 
                - 05C0D98D21D22119000B7B2A /* ThumbupUserItem.swift */,  | 
            |
| 801 | 
                - 05C0D98F21D2219A000B7B2A /* CommentItem.swift */,  | 
            |
| 765 | 
                + 0543E80A21D1DF4000A42807 /* GroupMemberItem.swift */,  | 
            |
| 766 | 
                + 05C0D98D21D22119000B7B2A /* PhotoThumbupUserItem.swift */,  | 
            |
| 767 | 
                + 05C0D98F21D2219A000B7B2A /* PhotoCommentItem.swift */,  | 
            |
| 802 | 768 | 
                05130FB121C9E703004EF1BE /* Reusable */,  | 
            
| 803 | 769 | 
                );  | 
            
| 804 | 770 | 
                path = Model;  | 
            
                @@ -807,18 +773,10 @@  | 
            ||
| 807 | 773 | 
                 		05130FAE21C9E691004EF1BE /* Repositories */ = {
               | 
            
| 808 | 774 | 
                isa = PBXGroup;  | 
            
| 809 | 775 | 
                children = (  | 
            
| 810 | 
                - A69FFA841E7002B50006FEE0 /* UserInfoRepository.swift */,  | 
            |
| 811 | 776 | 
                057CA9C521DCA2C900FB7D03 /* PhotoRepository.swift */,  | 
            
| 812 | 
                - A69FFAD61E70047E0006FEE0 /* HomePhotoRepository.swift */,  | 
            |
| 813 | 
                - 0540C8B01F8C9A640044FCC5 /* GroupPhotoRepository.swift */,  | 
            |
| 814 | 777 | 
                057CA9C921DCA70B00FB7D03 /* GroupRepository.swift */,  | 
            
| 815 | 
                - A69FFAE61E70047E0006FEE0 /* PhotoGroupRepository.swift */,  | 
            |
| 816 | 778 | 
                057CA9CD21DDAE8100FB7D03 /* GroupDetailRepository.swift */,  | 
            
| 817 | 
                - 0543E80C21D1E2EA00A42807 /* PhotoGroupDetailRepository.swift */,  | 
            |
| 818 | 
                - A69FFAED1E70047E0006FEE0 /* OrderRepository.swift */,  | 
            |
| 819 | 
                - 059AA62821BA855000485188 /* MessageRepository.swift */,  | 
            |
| 820 | 
                - A69FFADC1E70047E0006FEE0 /* MessageListRepository.swift */,  | 
            |
| 821 | 
                - 05C0D99521D22AA7000B7B2A /* PhotoDetailRepository.swift */,  | 
            |
| 779 | 
                + 05B1925E2244C929001102A1 /* Implementation */,  | 
            |
| 822 | 780 | 
                05C0D99821D23119000B7B2A /* Remote */,  | 
            
| 823 | 781 | 
                05130FB921C9EAA8004EF1BE /* Persistence */,  | 
            
| 824 | 782 | 
                );  | 
            
                @@ -828,8 +786,10 @@  | 
            ||
| 828 | 786 | 
                 		05130FB121C9E703004EF1BE /* Reusable */ = {
               | 
            
| 829 | 787 | 
                isa = PBXGroup;  | 
            
| 830 | 788 | 
                children = (  | 
            
| 789 | 
                + 057CA9CF21DDB7DD00FB7D03 /* NetworkArrayData.swift */,  | 
            |
| 831 | 790 | 
                0506441E1F8D09C00035857E /* StatusModel.swift */,  | 
            
| 832 | 791 | 
                0540C8B21F8CA07E0044FCC5 /* FileModel.swift */,  | 
            
| 792 | 
                + 0546D9842242460700742939 /* OriginData.swift */,  | 
            |
| 833 | 793 | 
                );  | 
            
| 834 | 794 | 
                path = Reusable;  | 
            
| 835 | 795 | 
                sourceTree = "<group>";  | 
            
                @@ -837,7 +797,6 @@  | 
            ||
| 837 | 797 | 
                 		05130FB921C9EAA8004EF1BE /* Persistence */ = {
               | 
            
| 838 | 798 | 
                isa = PBXGroup;  | 
            
| 839 | 799 | 
                children = (  | 
            
| 840 | 
                - 420FDBEA1EA70A9600958CBD /* PhotoLocalStorage.swift */,  | 
            |
| 841 | 800 | 
                A69FFB081E700B700006FEE0 /* RecentGroupInfo.swift */,  | 
            
| 842 | 801 | 
                051310B721CB6958004EF1BE /* UserInfoStore.swift */,  | 
            
| 843 | 802 | 
                );  | 
            
                @@ -1008,7 +967,7 @@  | 
            ||
| 1008 | 967 | 
                children = (  | 
            
| 1009 | 968 | 
                A69FFAD51E70047E0006FEE0 /* HomeViewModel.swift */,  | 
            
| 1010 | 969 | 
                05130F2721C88D35004EF1BE /* ScanQRViewModel.swift */,  | 
            
| 1011 | 
                - 05A0E8A821C782D700EAB9A2 /* CreateGroupConfirmViewModel.swift */,  | 
            |
| 970 | 
                + 05A0E8A821C782D700EAB9A2 /* CreateGroupViewModel.swift */,  | 
            |
| 1012 | 971 | 
                );  | 
            
| 1013 | 972 | 
                path = Home;  | 
            
| 1014 | 973 | 
                sourceTree = "<group>";  | 
            
                @@ -1044,7 +1003,9 @@  | 
            ||
| 1044 | 1003 | 
                 		0543E80521D0CDDA00A42807 /* PhotoDetail */ = {
               | 
            
| 1045 | 1004 | 
                isa = PBXGroup;  | 
            
| 1046 | 1005 | 
                children = (  | 
            
| 1047 | 
                - A69FFAA41E7004700006FEE0 /* DetailPageViewModel.swift */,  | 
            |
| 1006 | 
                + A69FFAA41E7004700006FEE0 /* PhotoDetailViewModel.swift */,  | 
            |
| 1007 | 
                + 05594BFE2240BEDE002D4910 /* PhotoDetailListViewModel.swift */,  | 
            |
| 1008 | 
                + 05594C002240BF9C002D4910 /* PhotoPurchaseViewModel.swift */,  | 
            |
| 1048 | 1009 | 
                );  | 
            
| 1049 | 1010 | 
                path = PhotoDetail;  | 
            
| 1050 | 1011 | 
                sourceTree = "<group>";  | 
            
                @@ -1108,6 +1069,21 @@  | 
            ||
| 1108 | 1069 | 
                path = AlertAction;  | 
            
| 1109 | 1070 | 
                sourceTree = "<group>";  | 
            
| 1110 | 1071 | 
                };  | 
            
| 1072 | 
                +		05B1925E2244C929001102A1 /* Implementation */ = {
               | 
            |
| 1073 | 
                + isa = PBXGroup;  | 
            |
| 1074 | 
                + children = (  | 
            |
| 1075 | 
                + A69FFA841E7002B50006FEE0 /* UserInfoRepository.swift */,  | 
            |
| 1076 | 
                + A69FFAE61E70047E0006FEE0 /* PhotoGroupRepository.swift */,  | 
            |
| 1077 | 
                + 0543E80C21D1E2EA00A42807 /* PhotoGroupDetailRepository.swift */,  | 
            |
| 1078 | 
                + 05C0D99521D22AA7000B7B2A /* PhotoDetailRepository.swift */,  | 
            |
| 1079 | 
                + A69FFAD61E70047E0006FEE0 /* HomeRepository.swift */,  | 
            |
| 1080 | 
                + 0540C8B01F8C9A640044FCC5 /* GroupPhotoRepository.swift */,  | 
            |
| 1081 | 
                + 059AA62821BA855000485188 /* MessageRepository.swift */,  | 
            |
| 1082 | 
                + A69FFAED1E70047E0006FEE0 /* OrderRepository.swift */,  | 
            |
| 1083 | 
                + );  | 
            |
| 1084 | 
                + path = Implementation;  | 
            |
| 1085 | 
                + sourceTree = "<group>";  | 
            |
| 1086 | 
                + };  | 
            |
| 1111 | 1087 | 
                 		05C0D99321D22604000B7B2A /* Reusable */ = {
               | 
            
| 1112 | 1088 | 
                isa = PBXGroup;  | 
            
| 1113 | 1089 | 
                children = (  | 
            
                @@ -1126,14 +1102,14 @@  | 
            ||
| 1126 | 1102 | 
                05C0D9A321D28591000B7B2A /* UserInfoRemoteAPI.swift */,  | 
            
| 1127 | 1103 | 
                0535D6D821D32A89008D9403 /* WXUserInfoRemoteAPI.swift */,  | 
            
| 1128 | 1104 | 
                0535D6DA21D32A9E008D9403 /* GuestUserInfoRemoteAPI.swift */,  | 
            
| 1129 | 
                - 05B2C5EE21D48133008063B3 /* HomePhotoRemoteAPI.swift */,  | 
            |
| 1105 | 
                + 05B2C5EE21D48133008063B3 /* HomeRemoteAPI.swift */,  | 
            |
| 1130 | 1106 | 
                057CA9B921DC836B00FB7D03 /* GroupPhotoRemoteAPI.swift */,  | 
            
| 1131 | 1107 | 
                05B2C61C21D710C5008063B3 /* GroupRemoteAPI.swift */,  | 
            
| 1132 | 1108 | 
                05B2C62E21D754BD008063B3 /* GroupDetailRemoteAPI.swift */,  | 
            
| 1133 | 1109 | 
                05B2C62621D74E92008063B3 /* OrderRemoteAPI.swift */,  | 
            
| 1134 | 1110 | 
                05B2C62821D74F27008063B3 /* MessageRemoteAPI.swift */,  | 
            
| 1135 | 
                - 05B2C62221D72EAF008063B3 /* MessageListRemoteAPI.swift */,  | 
            |
| 1136 | 1111 | 
                05B2C62A21D750F1008063B3 /* FeedbackRemoteAPI.swift */,  | 
            
| 1112 | 
                + 054B6C44223F884600939FE6 /* PhotoDetailRemoteAPI.swift */,  | 
            |
| 1137 | 1113 | 
                );  | 
            
| 1138 | 1114 | 
                path = Remote;  | 
            
| 1139 | 1115 | 
                sourceTree = "<group>";  | 
            
                @@ -1232,16 +1208,14 @@  | 
            ||
| 1232 | 1208 | 
                isa = PBXGroup;  | 
            
| 1233 | 1209 | 
                children = (  | 
            
| 1234 | 1210 | 
                0513106A21CA3545004EF1BE /* PhotoDetailCoordinator.swift */,  | 
            
| 1235 | 
                - A69FFAA01E7004700006FEE0 /* DetailPageHeadCell.swift */,  | 
            |
| 1236 | 
                - A69FFAA21E7004700006FEE0 /* DetailPagePhotoCell.swift */,  | 
            |
| 1237 | 
                - A69FFAA11E7004700006FEE0 /* DetailPageNameCell.swift */,  | 
            |
| 1238 | 
                - A69FFAA51E7004700006FEE0 /* DetailZanImagesCell.swift */,  | 
            |
| 1239 | 
                - A69FFA9E1E7004700006FEE0 /* DetailCommentCell.swift */,  | 
            |
| 1211 | 
                + A69FFAA31E7004700006FEE0 /* PhotoDetailViewController.swift */,  | 
            |
| 1212 | 
                + A69FFA9E1E7004700006FEE0 /* PhotoDetailCommentCell.swift */,  | 
            |
| 1213 | 
                + 05594C022240E94E002D4910 /* PhotoDetailImageCell.swift */,  | 
            |
| 1240 | 1214 | 
                A69FFAA61E7004700006FEE0 /* ImageCell.swift */,  | 
            
| 1241 | 
                - A69FFAA31E7004700006FEE0 /* DetailPageController.swift */,  | 
            |
| 1215 | 
                + 0546D98D2243782300742939 /* ShareView.swift */,  | 
            |
| 1242 | 1216 | 
                A69FFAA81E7004700006FEE0 /* ShareController.swift */,  | 
            
| 1243 | 
                - A69FFAA91E7004700006FEE0 /* ShowFullPicController.swift */,  | 
            |
| 1244 | 
                - A69FFB881E7018CC0006FEE0 /* Detail.storyboard */,  | 
            |
| 1217 | 
                + A69FFAA91E7004700006FEE0 /* PhotoPreviewViewController.swift */,  | 
            |
| 1218 | 
                + A69FFB881E7018CC0006FEE0 /* PhotoDetail.storyboard */,  | 
            |
| 1245 | 1219 | 
                );  | 
            
| 1246 | 1220 | 
                path = PhotoDetail;  | 
            
| 1247 | 1221 | 
                sourceTree = "<group>";  | 
            
                @@ -1280,10 +1254,10 @@  | 
            ||
| 1280 | 1254 | 
                children = (  | 
            
| 1281 | 1255 | 
                0513106821CA34D6004EF1BE /* GroupDetailCoordinator.swift */,  | 
            
| 1282 | 1256 | 
                A69FFAB11E7004700006FEE0 /* GroupDetailViewController.swift */,  | 
            
| 1283 | 
                - A69FFAB41E7004700006FEE0 /* GroupMemberController.swift */,  | 
            |
| 1284 | 
                - A69FFAB61E7004700006FEE0 /* MemberCell.swift */,  | 
            |
| 1285 | 
                - A69FFAAE1E7004700006FEE0 /* ChangeGroupNameController.swift */,  | 
            |
| 1286 | 
                - A69FFAB71E7004700006FEE0 /* ShowGroupQRController.swift */,  | 
            |
| 1257 | 
                + 0530951A221AB3EC00408D34 /* GroupDetailMemeberView.swift */,  | 
            |
| 1258 | 
                + A69FFAB41E7004700006FEE0 /* GroupMemberViewController.swift */,  | 
            |
| 1259 | 
                + A69FFAB61E7004700006FEE0 /* GroupMemberCell.swift */,  | 
            |
| 1260 | 
                + A69FFAAE1E7004700006FEE0 /* GroupNameModificationViewController.swift */,  | 
            |
| 1287 | 1261 | 
                A69FFB8A1E7018CC0006FEE0 /* GroupDetail.storyboard */,  | 
            
| 1288 | 1262 | 
                );  | 
            
| 1289 | 1263 | 
                path = GroupDetail;  | 
            
                @@ -1323,7 +1297,6 @@  | 
            ||
| 1323 | 1297 | 
                05130F2E21C94B32004EF1BE /* PaiaiUIKit.framework */,  | 
            
| 1324 | 1298 | 
                05130F6A21C95373004EF1BE /* PaiaiDataKit.framework */,  | 
            
| 1325 | 1299 | 
                05130F8E21C9E5E8004EF1BE /* Paiai_iOS.framework */,  | 
            
| 1326 | 
                - 0521144321EF38B60047C55A /* PaiaiDataKitTests.xctest */,  | 
            |
| 1327 | 1300 | 
                );  | 
            
| 1328 | 1301 | 
                name = Products;  | 
            
| 1329 | 1302 | 
                sourceTree = "<group>";  | 
            
                @@ -1478,26 +1451,6 @@  | 
            ||
| 1478 | 1451 | 
                productReference = 05130F8E21C9E5E8004EF1BE /* Paiai_iOS.framework */;  | 
            
| 1479 | 1452 | 
                productType = "com.apple.product-type.framework";  | 
            
| 1480 | 1453 | 
                };  | 
            
| 1481 | 
                -		0521144221EF38B60047C55A /* PaiaiDataKitTests */ = {
               | 
            |
| 1482 | 
                - isa = PBXNativeTarget;  | 
            |
| 1483 | 
                - buildConfigurationList = 0521144B21EF38B60047C55A /* Build configuration list for PBXNativeTarget "PaiaiDataKitTests" */;  | 
            |
| 1484 | 
                - buildPhases = (  | 
            |
| 1485 | 
                - 0521143F21EF38B60047C55A /* Sources */,  | 
            |
| 1486 | 
                - 0521144021EF38B60047C55A /* Frameworks */,  | 
            |
| 1487 | 
                - 0521144121EF38B60047C55A /* Resources */,  | 
            |
| 1488 | 
                - 0521145021EF3C090047C55A /* ShellScript */,  | 
            |
| 1489 | 
                - );  | 
            |
| 1490 | 
                - buildRules = (  | 
            |
| 1491 | 
                - );  | 
            |
| 1492 | 
                - dependencies = (  | 
            |
| 1493 | 
                - 0521144A21EF38B60047C55A /* PBXTargetDependency */,  | 
            |
| 1494 | 
                - 0521144F21EF3A440047C55A /* PBXTargetDependency */,  | 
            |
| 1495 | 
                - );  | 
            |
| 1496 | 
                - name = PaiaiDataKitTests;  | 
            |
| 1497 | 
                - productName = PaiaiDataKitTests;  | 
            |
| 1498 | 
                - productReference = 0521144321EF38B60047C55A /* PaiaiDataKitTests.xctest */;  | 
            |
| 1499 | 
                - productType = "com.apple.product-type.bundle.unit-test";  | 
            |
| 1500 | 
                - };  | 
            |
| 1501 | 1454 | 
                 		6CEBD0FE1CA8D680004DBDE0 /* Paiai */ = {
               | 
            
| 1502 | 1455 | 
                isa = PBXNativeTarget;  | 
            
| 1503 | 1456 | 
                buildConfigurationList = 6CEBD1111CA8D680004DBDE0 /* Build configuration list for PBXNativeTarget "Paiai" */;  | 
            
                @@ -1546,12 +1499,6 @@  | 
            ||
| 1546 | 1499 | 
                DevelopmentTeam = Q38447SL4M;  | 
            
| 1547 | 1500 | 
                ProvisioningStyle = Automatic;  | 
            
| 1548 | 1501 | 
                };  | 
            
| 1549 | 
                -					0521144221EF38B60047C55A = {
               | 
            |
| 1550 | 
                - CreatedOnToolsVersion = 10.1;  | 
            |
| 1551 | 
                - DevelopmentTeam = Q38447SL4M;  | 
            |
| 1552 | 
                - ProvisioningStyle = Automatic;  | 
            |
| 1553 | 
                - TestTargetID = 6CEBD0FE1CA8D680004DBDE0;  | 
            |
| 1554 | 
                - };  | 
            |
| 1555 | 1502 | 
                 					6CEBD0FE1CA8D680004DBDE0 = {
               | 
            
| 1556 | 1503 | 
                CreatedOnToolsVersion = 7.3;  | 
            
| 1557 | 1504 | 
                DevelopmentTeam = Q38447SL4M;  | 
            
                @@ -1589,7 +1536,6 @@  | 
            ||
| 1589 | 1536 | 
                05130F8D21C9E5E8004EF1BE /* Paiai_iOS */,  | 
            
| 1590 | 1537 | 
                05130F2D21C94B32004EF1BE /* PaiaiUIKit */,  | 
            
| 1591 | 1538 | 
                05130F6921C95373004EF1BE /* PaiaiDataKit */,  | 
            
| 1592 | 
                - 0521144221EF38B60047C55A /* PaiaiDataKitTests */,  | 
            |
| 1593 | 1539 | 
                );  | 
            
| 1594 | 1540 | 
                };  | 
            
| 1595 | 1541 | 
                /* End PBXProject section */  | 
            
                @@ -1619,20 +1565,13 @@  | 
            ||
| 1619 | 1565 | 
                0572B2C921E30D8000EAD2A2 /* PhotoCell.xib in Resources */,  | 
            
| 1620 | 1566 | 
                0513105B21CA1D50004EF1BE /* Mine.storyboard in Resources */,  | 
            
| 1621 | 1567 | 
                0513105821CA1D50004EF1BE /* Main.storyboard in Resources */,  | 
            
| 1622 | 
                - 0513105C21CA1D50004EF1BE /* Detail.storyboard in Resources */,  | 
            |
| 1568 | 
                + 0513105C21CA1D50004EF1BE /* PhotoDetail.storyboard in Resources */,  | 
            |
| 1623 | 1569 | 
                0500C25E21E72E45009A7013 /* Assets.xcassets in Resources */,  | 
            
| 1624 | 1570 | 
                0513105A21CA1D50004EF1BE /* Message.storyboard in Resources */,  | 
            
| 1625 | 1571 | 
                0513105921CA1D50004EF1BE /* GroupDetail.storyboard in Resources */,  | 
            
| 1626 | 1572 | 
                );  | 
            
| 1627 | 1573 | 
                runOnlyForDeploymentPostprocessing = 0;  | 
            
| 1628 | 1574 | 
                };  | 
            
| 1629 | 
                -		0521144121EF38B60047C55A /* Resources */ = {
               | 
            |
| 1630 | 
                - isa = PBXResourcesBuildPhase;  | 
            |
| 1631 | 
                - buildActionMask = 2147483647;  | 
            |
| 1632 | 
                - files = (  | 
            |
| 1633 | 
                - );  | 
            |
| 1634 | 
                - runOnlyForDeploymentPostprocessing = 0;  | 
            |
| 1635 | 
                - };  | 
            |
| 1636 | 1575 | 
                 		6CEBD0FD1CA8D680004DBDE0 /* Resources */ = {
               | 
            
| 1637 | 1576 | 
                isa = PBXResourcesBuildPhase;  | 
            
| 1638 | 1577 | 
                buildActionMask = 2147483647;  | 
            
                @@ -1646,31 +1585,13 @@  | 
            ||
| 1646 | 1585 | 
                /* End PBXResourcesBuildPhase section */  | 
            
| 1647 | 1586 | 
                 | 
            
| 1648 | 1587 | 
                /* Begin PBXShellScriptBuildPhase section */  | 
            
| 1649 | 
                -		0521145021EF3C090047C55A /* ShellScript */ = {
               | 
            |
| 1650 | 
                - isa = PBXShellScriptBuildPhase;  | 
            |
| 1651 | 
                - buildActionMask = 2147483647;  | 
            |
| 1652 | 
                - files = (  | 
            |
| 1653 | 
                - );  | 
            |
| 1654 | 
                - inputFileListPaths = (  | 
            |
| 1655 | 
                - );  | 
            |
| 1656 | 
                - inputPaths = (  | 
            |
| 1657 | 
                - );  | 
            |
| 1658 | 
                - outputFileListPaths = (  | 
            |
| 1659 | 
                - );  | 
            |
| 1660 | 
                - outputPaths = (  | 
            |
| 1661 | 
                - );  | 
            |
| 1662 | 
                - runOnlyForDeploymentPostprocessing = 0;  | 
            |
| 1663 | 
                - shellPath = /bin/sh;  | 
            |
| 1664 | 
                - shellScript = "/usr/local/bin/carthage copy-frameworks\n\n";  | 
            |
| 1665 | 
                - };  | 
            |
| 1666 | 1588 | 
                 		05D5F0C22015E55000BC890B /* Run Script */ = {
               | 
            
| 1667 | 1589 | 
                isa = PBXShellScriptBuildPhase;  | 
            
| 1668 | 
                - buildActionMask = 2147483647;  | 
            |
| 1590 | 
                + buildActionMask = 12;  | 
            |
| 1669 | 1591 | 
                files = (  | 
            
| 1670 | 1592 | 
                );  | 
            
| 1671 | 1593 | 
                inputPaths = (  | 
            
| 1672 | 1594 | 
                "$(SRCROOT)/Carthage/Build/iOS/SQLite.framework",  | 
            
| 1673 | 
                - "$(SRCROOT)/Carthage/Build/iOS/ESPullToRefresh.framework",  | 
            |
| 1674 | 1595 | 
                "$(SRCROOT)/Carthage/Build/iOS/RxCocoa.framework",  | 
            
| 1675 | 1596 | 
                "$(SRCROOT)/Carthage/Build/iOS/RxSwift.framework",  | 
            
| 1676 | 1597 | 
                "$(SRCROOT)/Carthage/Build/iOS/RxDataSources.framework",  | 
            
                @@ -1682,7 +1603,6 @@  | 
            ||
| 1682 | 1603 | 
                name = "Run Script";  | 
            
| 1683 | 1604 | 
                outputPaths = (  | 
            
| 1684 | 1605 | 
                "$(DERIVED_FILE_DIR)/$(FRAMEWORKS_FOLDER_PATH)/SQLite.framework",  | 
            
| 1685 | 
                - "$(DERIVED_FILE_DIR)/$(FRAMEWORKS_FOLDER_PATH)/ESPullToRefresh.framework",  | 
            |
| 1686 | 1606 | 
                "$(DERIVED_FILE_DIR)/$(FRAMEWORKS_FOLDER_PATH)/RxCocoa.framework",  | 
            
| 1687 | 1607 | 
                "$(DERIVED_FILE_DIR)/$(FRAMEWORKS_FOLDER_PATH)/RxSwift.framework",  | 
            
| 1688 | 1608 | 
                "$(DERIVED_FILE_DIR)/$(FRAMEWORKS_FOLDER_PATH)/RxDataSources.framework",  | 
            
                @@ -1805,37 +1725,34 @@  | 
            ||
| 1805 | 1725 | 
                0513102421CA1B67004EF1BE /* Interfaces.swift in Sources */,  | 
            
| 1806 | 1726 | 
                0513102521CA1B67004EF1BE /* NetworkApi.swift in Sources */,  | 
            
| 1807 | 1727 | 
                0513102621CA1B67004EF1BE /* Resource.swift in Sources */,  | 
            
| 1728 | 
                + 05594C012240BF9C002D4910 /* PhotoPurchaseViewModel.swift in Sources */,  | 
            |
| 1808 | 1729 | 
                0513102821CA1B67004EF1BE /* NetWorkCache.swift in Sources */,  | 
            
| 1809 | 1730 | 
                0535D6DB21D32A9E008D9403 /* GuestUserInfoRemoteAPI.swift in Sources */,  | 
            
| 1810 | 1731 | 
                05B2C63121D75A1B008063B3 /* ContentResource.swift in Sources */,  | 
            
| 1811 | 1732 | 
                057CA9CA21DCA70B00FB7D03 /* GroupRepository.swift in Sources */,  | 
            
| 1812 | 1733 | 
                0513102921CA1B67004EF1BE /* Result.swift in Sources */,  | 
            
| 1813 | 1734 | 
                05C0D9A421D28591000B7B2A /* UserInfoRemoteAPI.swift in Sources */,  | 
            
| 1814 | 
                - 0513102B21CA1B67004EF1BE /* HomePhotoRepository.swift in Sources */,  | 
            |
| 1735 | 
                + 0513102B21CA1B67004EF1BE /* HomeRepository.swift in Sources */,  | 
            |
| 1815 | 1736 | 
                0535D6D921D32A89008D9403 /* WXUserInfoRemoteAPI.swift in Sources */,  | 
            
| 1816 | 1737 | 
                0513102C21CA1B67004EF1BE /* OrderRepository.swift in Sources */,  | 
            
| 1817 | 1738 | 
                057CA9BA21DC836B00FB7D03 /* GroupPhotoRemoteAPI.swift in Sources */,  | 
            
| 1818 | 1739 | 
                0513102D21CA1B67004EF1BE /* GroupPhotoRepository.swift in Sources */,  | 
            
| 1819 | 
                - 05C0D98E21D22119000B7B2A /* ThumbupUserItem.swift in Sources */,  | 
            |
| 1740 | 
                + 05C0D98E21D22119000B7B2A /* PhotoThumbupUserItem.swift in Sources */,  | 
            |
| 1820 | 1741 | 
                05C71C0821DDBD55003E7CEE /* JSONCode.swift in Sources */,  | 
            
| 1821 | 1742 | 
                0513102E21CA1B67004EF1BE /* PhotoGroupRepository.swift in Sources */,  | 
            
| 1822 | 1743 | 
                051310B821CB6958004EF1BE /* UserInfoStore.swift in Sources */,  | 
            
| 1823 | 
                - 05B2C5EF21D48133008063B3 /* HomePhotoRemoteAPI.swift in Sources */,  | 
            |
| 1824 | 
                - 057CA9D021DDB7DD00FB7D03 /* NetWorkData.swift in Sources */,  | 
            |
| 1825 | 
                - 0513102F21CA1B67004EF1BE /* GroupDetailModel.swift in Sources */,  | 
            |
| 1744 | 
                + 05B2C5EF21D48133008063B3 /* HomeRemoteAPI.swift in Sources */,  | 
            |
| 1745 | 
                + 057CA9D021DDB7DD00FB7D03 /* NetworkArrayData.swift in Sources */,  | 
            |
| 1826 | 1746 | 
                057CA9CE21DDAE8100FB7D03 /* GroupDetailRepository.swift in Sources */,  | 
            
| 1827 | 
                - 0513103021CA1B67004EF1BE /* MessageListRepository.swift in Sources */,  | 
            |
| 1828 | 1747 | 
                0543E80B21D1DF4000A42807 /* GroupMemberItem.swift in Sources */,  | 
            
| 1829 | 1748 | 
                0513103121CA1B67004EF1BE /* MessageRepository.swift in Sources */,  | 
            
| 1830 | 1749 | 
                0543E80721D0CDFA00A42807 /* MineFeedbackViewModel.swift in Sources */,  | 
            
| 1831 | 
                - 0513103221CA1B67004EF1BE /* DetailModel.swift in Sources */,  | 
            |
| 1832 | 1750 | 
                0513103321CA1B67004EF1BE /* UserInfoRepository.swift in Sources */,  | 
            
| 1833 | 
                - 0513103421CA1B67004EF1BE /* PhotoLocalStorage.swift in Sources */,  | 
            |
| 1834 | 1751 | 
                0513103521CA1B67004EF1BE /* RecentGroupInfo.swift in Sources */,  | 
            
| 1835 | 1752 | 
                0513103921CA1B67004EF1BE /* HomeViewModel.swift in Sources */,  | 
            
| 1836 | 1753 | 
                0543E80F21D1FD1100A42807 /* GroupDetailItem.swift in Sources */,  | 
            
| 1837 | 1754 | 
                0513103A21CA1B67004EF1BE /* GroupViewModel.swift in Sources */,  | 
            
| 1838 | 
                - 05C0D99021D2219A000B7B2A /* CommentItem.swift in Sources */,  | 
            |
| 1755 | 
                + 05C0D99021D2219A000B7B2A /* PhotoCommentItem.swift in Sources */,  | 
            |
| 1839 | 1756 | 
                0513103B21CA1B67004EF1BE /* GroupDetailViewModel.swift in Sources */,  | 
            
| 1840 | 1757 | 
                05B2C62B21D750F1008063B3 /* FeedbackRemoteAPI.swift in Sources */,  | 
            
| 1841 | 1758 | 
                0513103C21CA1B67004EF1BE /* GroupMemberViewModel.swift in Sources */,  | 
            
                @@ -1843,19 +1760,21 @@  | 
            ||
| 1843 | 1760 | 
                0513103E21CA1B67004EF1BE /* MineOrderViewModel.swift in Sources */,  | 
            
| 1844 | 1761 | 
                05B2C62721D74E92008063B3 /* OrderRemoteAPI.swift in Sources */,  | 
            
| 1845 | 1762 | 
                05B2C62921D74F27008063B3 /* MessageRemoteAPI.swift in Sources */,  | 
            
| 1846 | 
                - 0513103F21CA1B67004EF1BE /* DetailPageViewModel.swift in Sources */,  | 
            |
| 1763 | 
                + 0513103F21CA1B67004EF1BE /* PhotoDetailViewModel.swift in Sources */,  | 
            |
| 1764 | 
                + 054B6C45223F884600939FE6 /* PhotoDetailRemoteAPI.swift in Sources */,  | 
            |
| 1847 | 1765 | 
                0513104021CA1B67004EF1BE /* MessageListViewModel.swift in Sources */,  | 
            
| 1848 | 1766 | 
                053E127521F5A72000A64893 /* DataError.swift in Sources */,  | 
            
| 1849 | 1767 | 
                05B2C61D21D710C5008063B3 /* GroupRemoteAPI.swift in Sources */,  | 
            
| 1850 | 1768 | 
                0513104121CA1B67004EF1BE /* MessageViewModel.swift in Sources */,  | 
            
| 1851 | 
                - 0513104221CA1B67004EF1BE /* CreateGroupConfirmViewModel.swift in Sources */,  | 
            |
| 1769 | 
                + 0513104221CA1B67004EF1BE /* CreateGroupViewModel.swift in Sources */,  | 
            |
| 1852 | 1770 | 
                0513104321CA1B67004EF1BE /* ScanQRViewModel.swift in Sources */,  | 
            
| 1853 | 1771 | 
                05130FB721C9E80F004EF1BE /* MessageListItem.swift in Sources */,  | 
            
| 1854 | 1772 | 
                05B2C62121D727AA008063B3 /* StatusResource.swift in Sources */,  | 
            
| 1855 | 1773 | 
                051310C021CB6EF4004EF1BE /* UserInfo.swift in Sources */,  | 
            
| 1774 | 
                + 05594BFF2240BEDE002D4910 /* PhotoDetailListViewModel.swift in Sources */,  | 
            |
| 1856 | 1775 | 
                05130FB521C9E7CE004EF1BE /* MessageItem.swift in Sources */,  | 
            
| 1857 | 1776 | 
                057CA9C621DCA2C900FB7D03 /* PhotoRepository.swift in Sources */,  | 
            
| 1858 | 
                - 05B2C62321D72EAF008063B3 /* MessageListRemoteAPI.swift in Sources */,  | 
            |
| 1777 | 
                + 0546D9852242460700742939 /* OriginData.swift in Sources */,  | 
            |
| 1859 | 1778 | 
                05B2C62F21D754BD008063B3 /* GroupDetailRemoteAPI.swift in Sources */,  | 
            
| 1860 | 1779 | 
                05130FB321C9E76A004EF1BE /* GroupItem.swift in Sources */,  | 
            
| 1861 | 1780 | 
                05130FB021C9E6CD004EF1BE /* OrderItem.swift in Sources */,  | 
            
                @@ -1866,13 +1785,13 @@  | 
            ||
| 1866 | 1785 | 
                isa = PBXSourcesBuildPhase;  | 
            
| 1867 | 1786 | 
                buildActionMask = 2147483647;  | 
            
| 1868 | 1787 | 
                files = (  | 
            
| 1788 | 
                + 0546D98E2243782300742939 /* ShareView.swift in Sources */,  | 
            |
| 1869 | 1789 | 
                051310B621CB675A004EF1BE /* UIImageView+Kingfisher.swift in Sources */,  | 
            
| 1870 | 1790 | 
                05130FDD21CA1B04004EF1BE /* GroupViewController.swift in Sources */,  | 
            
| 1871 | 
                - 05130FDF21CA1B04004EF1BE /* MemberCell.swift in Sources */,  | 
            |
| 1791 | 
                + 05130FDF21CA1B04004EF1BE /* GroupMemberCell.swift in Sources */,  | 
            |
| 1872 | 1792 | 
                05130FE021CA1B04004EF1BE /* GroupDetailViewController.swift in Sources */,  | 
            
| 1873 | 
                - 05130FE121CA1B04004EF1BE /* GroupMemberController.swift in Sources */,  | 
            |
| 1874 | 
                - 05130FE221CA1B04004EF1BE /* ChangeGroupNameController.swift in Sources */,  | 
            |
| 1875 | 
                - 05130FE321CA1B04004EF1BE /* ShowGroupQRController.swift in Sources */,  | 
            |
| 1793 | 
                + 05130FE121CA1B04004EF1BE /* GroupMemberViewController.swift in Sources */,  | 
            |
| 1794 | 
                + 05130FE221CA1B04004EF1BE /* GroupNameModificationViewController.swift in Sources */,  | 
            |
| 1876 | 1795 | 
                055EFAD7221A4DB400450AD5 /* GroupQRView.swift in Sources */,  | 
            
| 1877 | 1796 | 
                05130FE421CA1B04004EF1BE /* MessageCommentAndThumbupCell.swift in Sources */,  | 
            
| 1878 | 1797 | 
                05D3A3CD22000C3A00A29A20 /* GroupCoordinator.swift in Sources */,  | 
            
                @@ -1880,6 +1799,7 @@  | 
            ||
| 1880 | 1799 | 
                05130FE621CA1B04004EF1BE /* MessageCoordinator.swift in Sources */,  | 
            
| 1881 | 1800 | 
                05130FE721CA1B04004EF1BE /* MessageViewController.swift in Sources */,  | 
            
| 1882 | 1801 | 
                05130FE821CA1B04004EF1BE /* MessageListViewController.swift in Sources */,  | 
            
| 1802 | 
                + 0530951B221AB3EC00408D34 /* GroupDetailMemeberView.swift in Sources */,  | 
            |
| 1883 | 1803 | 
                0513106921CA34D6004EF1BE /* GroupDetailCoordinator.swift in Sources */,  | 
            
| 1884 | 1804 | 
                05130FEA21CA1B04004EF1BE /* GroupCell.swift in Sources */,  | 
            
| 1885 | 1805 | 
                05130FEB21CA1B04004EF1BE /* OrderCell.swift in Sources */,  | 
            
                @@ -1887,18 +1807,15 @@  | 
            ||
| 1887 | 1807 | 
                05130FED21CA1B04004EF1BE /* MineViewController.swift in Sources */,  | 
            
| 1888 | 1808 | 
                05130FEE21CA1B04004EF1BE /* MineGroupViewController.swift in Sources */,  | 
            
| 1889 | 1809 | 
                05130FEF21CA1B04004EF1BE /* MineFeedbackViewController.swift in Sources */,  | 
            
| 1810 | 
                + 05594C032240E94E002D4910 /* PhotoDetailImageCell.swift in Sources */,  | 
            |
| 1890 | 1811 | 
                05130FF021CA1B04004EF1BE /* MineOrderViewController.swift in Sources */,  | 
            
| 1891 | 1812 | 
                05130FF121CA1B04004EF1BE /* MineAboutViewController.swift in Sources */,  | 
            
| 1892 | 
                - 05130FF321CA1B04004EF1BE /* DetailPageHeadCell.swift in Sources */,  | 
            |
| 1893 | 
                - 05130FF421CA1B04004EF1BE /* DetailPagePhotoCell.swift in Sources */,  | 
            |
| 1894 | 
                - 05130FF521CA1B04004EF1BE /* DetailPageNameCell.swift in Sources */,  | 
            |
| 1895 | 
                - 05130FF621CA1B04004EF1BE /* DetailZanImagesCell.swift in Sources */,  | 
            |
| 1896 | 
                - 05130FF721CA1B04004EF1BE /* DetailCommentCell.swift in Sources */,  | 
            |
| 1813 | 
                + 05130FF721CA1B04004EF1BE /* PhotoDetailCommentCell.swift in Sources */,  | 
            |
| 1897 | 1814 | 
                0513106B21CA3545004EF1BE /* PhotoDetailCoordinator.swift in Sources */,  | 
            
| 1898 | 1815 | 
                05130FF821CA1B04004EF1BE /* ImageCell.swift in Sources */,  | 
            
| 1899 | 
                - 05130FF921CA1B04004EF1BE /* DetailPageController.swift in Sources */,  | 
            |
| 1816 | 
                + 05130FF921CA1B04004EF1BE /* PhotoDetailViewController.swift in Sources */,  | 
            |
| 1900 | 1817 | 
                05130FFB21CA1B04004EF1BE /* ShareController.swift in Sources */,  | 
            
| 1901 | 
                - 05130FFC21CA1B04004EF1BE /* ShowFullPicController.swift in Sources */,  | 
            |
| 1818 | 
                + 05130FFC21CA1B04004EF1BE /* PhotoPreviewViewController.swift in Sources */,  | 
            |
| 1902 | 1819 | 
                05130FD721CA1ADF004EF1BE /* HomeCoordinator.swift in Sources */,  | 
            
| 1903 | 1820 | 
                05130FD821CA1AE0004EF1BE /* HomeViewController.swift in Sources */,  | 
            
| 1904 | 1821 | 
                05130FD921CA1AE0004EF1BE /* CreateGroupConfirmViewController.swift in Sources */,  | 
            
                @@ -1911,14 +1828,6 @@  | 
            ||
| 1911 | 1828 | 
                );  | 
            
| 1912 | 1829 | 
                runOnlyForDeploymentPostprocessing = 0;  | 
            
| 1913 | 1830 | 
                };  | 
            
| 1914 | 
                -		0521143F21EF38B60047C55A /* Sources */ = {
               | 
            |
| 1915 | 
                - isa = PBXSourcesBuildPhase;  | 
            |
| 1916 | 
                - buildActionMask = 2147483647;  | 
            |
| 1917 | 
                - files = (  | 
            |
| 1918 | 
                - 0521144621EF38B60047C55A /* PaiaiDataKitTests.swift in Sources */,  | 
            |
| 1919 | 
                - );  | 
            |
| 1920 | 
                - runOnlyForDeploymentPostprocessing = 0;  | 
            |
| 1921 | 
                - };  | 
            |
| 1922 | 1831 | 
                 		6CEBD0FB1CA8D680004DBDE0 /* Sources */ = {
               | 
            
| 1923 | 1832 | 
                isa = PBXSourcesBuildPhase;  | 
            
| 1924 | 1833 | 
                buildActionMask = 2147483647;  | 
            
                @@ -1955,25 +1864,15 @@  | 
            ||
| 1955 | 1864 | 
                target = 05130F6921C95373004EF1BE /* PaiaiDataKit */;  | 
            
| 1956 | 1865 | 
                targetProxy = 051310A921CA451B004EF1BE /* PBXContainerItemProxy */;  | 
            
| 1957 | 1866 | 
                };  | 
            
| 1958 | 
                -		0521144A21EF38B60047C55A /* PBXTargetDependency */ = {
               | 
            |
| 1959 | 
                - isa = PBXTargetDependency;  | 
            |
| 1960 | 
                - target = 05130F6921C95373004EF1BE /* PaiaiDataKit */;  | 
            |
| 1961 | 
                - targetProxy = 0521144921EF38B60047C55A /* PBXContainerItemProxy */;  | 
            |
| 1962 | 
                - };  | 
            |
| 1963 | 
                -		0521144F21EF3A440047C55A /* PBXTargetDependency */ = {
               | 
            |
| 1964 | 
                - isa = PBXTargetDependency;  | 
            |
| 1965 | 
                - target = 6CEBD0FE1CA8D680004DBDE0 /* Paiai */;  | 
            |
| 1966 | 
                - targetProxy = 0521144E21EF3A440047C55A /* PBXContainerItemProxy */;  | 
            |
| 1967 | 
                - };  | 
            |
| 1968 | 1867 | 
                /* End PBXTargetDependency section */  | 
            
| 1969 | 1868 | 
                 | 
            
| 1970 | 1869 | 
                /* Begin PBXVariantGroup section */  | 
            
| 1971 | 
                -		A69FFB881E7018CC0006FEE0 /* Detail.storyboard */ = {
               | 
            |
| 1870 | 
                +		A69FFB881E7018CC0006FEE0 /* PhotoDetail.storyboard */ = {
               | 
            |
| 1972 | 1871 | 
                isa = PBXVariantGroup;  | 
            
| 1973 | 1872 | 
                children = (  | 
            
| 1974 | 1873 | 
                A69FFB891E7018CC0006FEE0 /* Base */,  | 
            
| 1975 | 1874 | 
                );  | 
            
| 1976 | 
                - name = Detail.storyboard;  | 
            |
| 1875 | 
                + name = PhotoDetail.storyboard;  | 
            |
| 1977 | 1876 | 
                sourceTree = "<group>";  | 
            
| 1978 | 1877 | 
                };  | 
            
| 1979 | 1878 | 
                 		A69FFB8A1E7018CC0006FEE0 /* GroupDetail.storyboard */ = {
               | 
            
                @@ -2094,7 +1993,7 @@  | 
            ||
| 2094 | 1993 | 
                CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = YES;  | 
            
| 2095 | 1994 | 
                CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;  | 
            
| 2096 | 1995 | 
                CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";  | 
            
| 2097 | 
                - CLANG_ENABLE_MODULES = YES;  | 
            |
| 1996 | 
                + CLANG_ENABLE_MODULES = NO;  | 
            |
| 2098 | 1997 | 
                CLANG_ENABLE_OBJC_WEAK = YES;  | 
            
| 2099 | 1998 | 
                CLANG_WARN_DOCUMENTATION_COMMENTS = YES;  | 
            
| 2100 | 1999 | 
                CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;  | 
            
                @@ -2142,7 +2041,7 @@  | 
            ||
| 2142 | 2041 | 
                CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = YES;  | 
            
| 2143 | 2042 | 
                CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;  | 
            
| 2144 | 2043 | 
                CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";  | 
            
| 2145 | 
                - CLANG_ENABLE_MODULES = YES;  | 
            |
| 2044 | 
                + CLANG_ENABLE_MODULES = NO;  | 
            |
| 2146 | 2045 | 
                CLANG_ENABLE_OBJC_WEAK = YES;  | 
            
| 2147 | 2046 | 
                CLANG_WARN_DOCUMENTATION_COMMENTS = YES;  | 
            
| 2148 | 2047 | 
                CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;  | 
            
                @@ -2259,61 +2158,6 @@  | 
            ||
| 2259 | 2158 | 
                };  | 
            
| 2260 | 2159 | 
                name = Release;  | 
            
| 2261 | 2160 | 
                };  | 
            
| 2262 | 
                -		0521144C21EF38B60047C55A /* Debug */ = {
               | 
            |
| 2263 | 
                - isa = XCBuildConfiguration;  | 
            |
| 2264 | 
                -			buildSettings = {
               | 
            |
| 2265 | 
                - BUNDLE_LOADER = "$(TEST_HOST)";  | 
            |
| 2266 | 
                - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;  | 
            |
| 2267 | 
                - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";  | 
            |
| 2268 | 
                - CLANG_ENABLE_OBJC_WEAK = YES;  | 
            |
| 2269 | 
                - CLANG_WARN_DOCUMENTATION_COMMENTS = YES;  | 
            |
| 2270 | 
                - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;  | 
            |
| 2271 | 
                - CODE_SIGN_IDENTITY = "iPhone Developer";  | 
            |
| 2272 | 
                - CODE_SIGN_STYLE = Automatic;  | 
            |
| 2273 | 
                - DEVELOPMENT_TEAM = Q38447SL4M;  | 
            |
| 2274 | 
                - FRAMEWORK_SEARCH_PATHS = "$(PROJECT_DIR)/Carthage/Build/iOS";  | 
            |
| 2275 | 
                - GCC_C_LANGUAGE_STANDARD = gnu11;  | 
            |
| 2276 | 
                - INFOPLIST_FILE = PaiaiDataKitTests/Info.plist;  | 
            |
| 2277 | 
                - IPHONEOS_DEPLOYMENT_TARGET = 12.1;  | 
            |
| 2278 | 
                - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";  | 
            |
| 2279 | 
                - MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;  | 
            |
| 2280 | 
                - MTL_FAST_MATH = YES;  | 
            |
| 2281 | 
                - PRODUCT_BUNDLE_IDENTIFIER = FFIB.PaiaiDataKitTests;  | 
            |
| 2282 | 
                - PRODUCT_NAME = "$(TARGET_NAME)";  | 
            |
| 2283 | 
                - SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;  | 
            |
| 2284 | 
                - SWIFT_VERSION = 4.2;  | 
            |
| 2285 | 
                - TARGETED_DEVICE_FAMILY = "1,2";  | 
            |
| 2286 | 
                - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Paiai.app/Paiai";  | 
            |
| 2287 | 
                - };  | 
            |
| 2288 | 
                - name = Debug;  | 
            |
| 2289 | 
                - };  | 
            |
| 2290 | 
                -		0521144D21EF38B60047C55A /* Release */ = {
               | 
            |
| 2291 | 
                - isa = XCBuildConfiguration;  | 
            |
| 2292 | 
                -			buildSettings = {
               | 
            |
| 2293 | 
                - BUNDLE_LOADER = "$(TEST_HOST)";  | 
            |
| 2294 | 
                - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;  | 
            |
| 2295 | 
                - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";  | 
            |
| 2296 | 
                - CLANG_ENABLE_OBJC_WEAK = YES;  | 
            |
| 2297 | 
                - CLANG_WARN_DOCUMENTATION_COMMENTS = YES;  | 
            |
| 2298 | 
                - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;  | 
            |
| 2299 | 
                - CODE_SIGN_IDENTITY = "iPhone Developer";  | 
            |
| 2300 | 
                - CODE_SIGN_STYLE = Automatic;  | 
            |
| 2301 | 
                - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";  | 
            |
| 2302 | 
                - DEVELOPMENT_TEAM = Q38447SL4M;  | 
            |
| 2303 | 
                - FRAMEWORK_SEARCH_PATHS = "$(PROJECT_DIR)/Carthage/Build/iOS";  | 
            |
| 2304 | 
                - GCC_C_LANGUAGE_STANDARD = gnu11;  | 
            |
| 2305 | 
                - INFOPLIST_FILE = PaiaiDataKitTests/Info.plist;  | 
            |
| 2306 | 
                - IPHONEOS_DEPLOYMENT_TARGET = 12.1;  | 
            |
| 2307 | 
                - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";  | 
            |
| 2308 | 
                - MTL_FAST_MATH = YES;  | 
            |
| 2309 | 
                - PRODUCT_BUNDLE_IDENTIFIER = FFIB.PaiaiDataKitTests;  | 
            |
| 2310 | 
                - PRODUCT_NAME = "$(TARGET_NAME)";  | 
            |
| 2311 | 
                - SWIFT_VERSION = 4.2;  | 
            |
| 2312 | 
                - TARGETED_DEVICE_FAMILY = "1,2";  | 
            |
| 2313 | 
                - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Paiai.app/Paiai";  | 
            |
| 2314 | 
                - };  | 
            |
| 2315 | 
                - name = Release;  | 
            |
| 2316 | 
                - };  | 
            |
| 2317 | 2161 | 
                 		6CEBD10F1CA8D680004DBDE0 /* Debug */ = {
               | 
            
| 2318 | 2162 | 
                isa = XCBuildConfiguration;  | 
            
| 2319 | 2163 | 
                 			buildSettings = {
               | 
            
                @@ -2323,7 +2167,7 @@  | 
            ||
| 2323 | 2167 | 
                CLANG_ANALYZER_NONNULL = YES;  | 
            
| 2324 | 2168 | 
                CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";  | 
            
| 2325 | 2169 | 
                CLANG_CXX_LIBRARY = "libc++";  | 
            
| 2326 | 
                - CLANG_ENABLE_MODULES = YES;  | 
            |
| 2170 | 
                + CLANG_ENABLE_MODULES = NO;  | 
            |
| 2327 | 2171 | 
                CLANG_ENABLE_OBJC_ARC = YES;  | 
            
| 2328 | 2172 | 
                CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;  | 
            
| 2329 | 2173 | 
                CLANG_WARN_BOOL_CONVERSION = YES;  | 
            
                @@ -2384,7 +2228,7 @@  | 
            ||
| 2384 | 2228 | 
                CLANG_ANALYZER_NONNULL = YES;  | 
            
| 2385 | 2229 | 
                CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";  | 
            
| 2386 | 2230 | 
                CLANG_CXX_LIBRARY = "libc++";  | 
            
| 2387 | 
                - CLANG_ENABLE_MODULES = YES;  | 
            |
| 2231 | 
                + CLANG_ENABLE_MODULES = NO;  | 
            |
| 2388 | 2232 | 
                CLANG_ENABLE_OBJC_ARC = YES;  | 
            
| 2389 | 2233 | 
                CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;  | 
            
| 2390 | 2234 | 
                CLANG_WARN_BOOL_CONVERSION = YES;  | 
            
                @@ -2434,6 +2278,7 @@  | 
            ||
| 2434 | 2278 | 
                isa = XCBuildConfiguration;  | 
            
| 2435 | 2279 | 
                 			buildSettings = {
               | 
            
| 2436 | 2280 | 
                ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = "$(inherited)";  | 
            
| 2281 | 
                + ALWAYS_SEARCH_USER_PATHS = NO;  | 
            |
| 2437 | 2282 | 
                ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;  | 
            
| 2438 | 2283 | 
                CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = NO;  | 
            
| 2439 | 2284 | 
                CLANG_ENABLE_MODULES = NO;  | 
            
                @@ -2462,6 +2307,7 @@  | 
            ||
| 2462 | 2307 | 
                "$(inherited)",  | 
            
| 2463 | 2308 | 
                "$(PROJECT_DIR)/Paiai/wxSDK",  | 
            
| 2464 | 2309 | 
                );  | 
            
| 2310 | 
                + MACH_O_TYPE = mh_execute;  | 
            |
| 2465 | 2311 | 
                ONLY_ACTIVE_ARCH = YES;  | 
            
| 2466 | 2312 | 
                OTHER_LDFLAGS = "";  | 
            
| 2467 | 2313 | 
                OTHER_SWIFT_FLAGS = "-DDEBUG";  | 
            
                @@ -2480,6 +2326,7 @@  | 
            ||
| 2480 | 2326 | 
                isa = XCBuildConfiguration;  | 
            
| 2481 | 2327 | 
                 			buildSettings = {
               | 
            
| 2482 | 2328 | 
                ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = "$(inherited)";  | 
            
| 2329 | 
                + ALWAYS_SEARCH_USER_PATHS = NO;  | 
            |
| 2483 | 2330 | 
                ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;  | 
            
| 2484 | 2331 | 
                CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = NO;  | 
            
| 2485 | 2332 | 
                CLANG_ENABLE_MODULES = NO;  | 
            
                @@ -2507,6 +2354,7 @@  | 
            ||
| 2507 | 2354 | 
                "$(inherited)",  | 
            
| 2508 | 2355 | 
                "$(PROJECT_DIR)/Paiai/wxSDK",  | 
            
| 2509 | 2356 | 
                );  | 
            
| 2357 | 
                + MACH_O_TYPE = mh_execute;  | 
            |
| 2510 | 2358 | 
                ONLY_ACTIVE_ARCH = YES;  | 
            
| 2511 | 2359 | 
                OTHER_LDFLAGS = "";  | 
            
| 2512 | 2360 | 
                OTHER_SWIFT_FLAGS = "";  | 
            
                @@ -2551,15 +2399,6 @@  | 
            ||
| 2551 | 2399 | 
                defaultConfigurationIsVisible = 0;  | 
            
| 2552 | 2400 | 
                defaultConfigurationName = Release;  | 
            
| 2553 | 2401 | 
                };  | 
            
| 2554 | 
                -		0521144B21EF38B60047C55A /* Build configuration list for PBXNativeTarget "PaiaiDataKitTests" */ = {
               | 
            |
| 2555 | 
                - isa = XCConfigurationList;  | 
            |
| 2556 | 
                - buildConfigurations = (  | 
            |
| 2557 | 
                - 0521144C21EF38B60047C55A /* Debug */,  | 
            |
| 2558 | 
                - 0521144D21EF38B60047C55A /* Release */,  | 
            |
| 2559 | 
                - );  | 
            |
| 2560 | 
                - defaultConfigurationIsVisible = 0;  | 
            |
| 2561 | 
                - defaultConfigurationName = Release;  | 
            |
| 2562 | 
                - };  | 
            |
| 2563 | 2402 | 
                 		6CEBD0FA1CA8D680004DBDE0 /* Build configuration list for PBXProject "Paiai" */ = {
               | 
            
| 2564 | 2403 | 
                isa = XCConfigurationList;  | 
            
| 2565 | 2404 | 
                buildConfigurations = (  | 
            
                @@ -2,16 +2,4 @@  | 
            ||
| 2 | 2 | 
                <Bucket  | 
            
| 3 | 3 | 
                type = "1"  | 
            
| 4 | 4 | 
                version = "2.0">  | 
            
| 5 | 
                - <Breakpoints>  | 
            |
| 6 | 
                - <BreakpointProxy  | 
            |
| 7 | 
                - BreakpointExtensionID = "Xcode.Breakpoint.ExceptionBreakpoint">  | 
            |
| 8 | 
                - <BreakpointContent  | 
            |
| 9 | 
                - shouldBeEnabled = "Yes"  | 
            |
| 10 | 
                - ignoreCount = "0"  | 
            |
| 11 | 
                - continueAfterRunningActions = "No"  | 
            |
| 12 | 
                - scope = "0"  | 
            |
| 13 | 
                - stopOnStyle = "0">  | 
            |
| 14 | 
                - </BreakpointContent>  | 
            |
| 15 | 
                - </BreakpointProxy>  | 
            |
| 16 | 
                - </Breakpoints>  | 
            |
| 17 | 5 | 
                </Bucket>  | 
            
                @@ -59,6 +59,8 @@  | 
            ||
| 59 | 59 | 
                </array>  | 
            
| 60 | 60 | 
                <key>CFBundleVersion</key>  | 
            
| 61 | 61 | 
                <string>1</string>  | 
            
| 62 | 
                + <key>LSApplicationCategoryType</key>  | 
            |
| 63 | 
                + <string></string>  | 
            |
| 62 | 64 | 
                <key>LSApplicationQueriesSchemes</key>  | 
            
| 63 | 65 | 
                <array>  | 
            
| 64 | 66 | 
                <string>wechat</string>  | 
            
                @@ -81,34 +83,26 @@  | 
            ||
| 81 | 83 | 
                <key>NSAllowsArbitraryLoads</key>  | 
            
| 82 | 84 | 
                <true/>  | 
            
| 83 | 85 | 
                </dict>  | 
            
| 84 | 
                - <key>NSAppleMusicUsageDescription</key>  | 
            |
| 85 | 
                - <string>App需要您的同意,才能进行查看相册</string>  | 
            |
| 86 | 
                - <key>NSBluetoothPeripheralUsageDescription</key>  | 
            |
| 87 | 
                - <string>App需要您的同意,才能进行访问蓝牙</string>  | 
            |
| 88 | 
                - <key>NSCalendarsUsageDescription</key>  | 
            |
| 89 | 
                - <string>App需要您的同意,才能进行查看日历</string>  | 
            |
| 90 | 86 | 
                <key>NSCameraUsageDescription</key>  | 
            
| 91 | 87 | 
                <string>App需要您的同意,才能进行拍摄</string>  | 
            
| 92 | 
                - <key>NSContactsUsageDescription</key>  | 
            |
| 93 | 
                - <string>App需要您的同意,才能进行查看通讯录</string>  | 
            |
| 94 | 
                - <key>NSLocationAlwaysUsageDescription</key>  | 
            |
| 95 | 
                - <string>需要您的位置用于在参加旅行团时,方便导游集合团员。如果不允许,将无法更加快捷的集合</string>  | 
            |
| 96 | 
                - <key>NSLocationUsageDescription</key>  | 
            |
| 97 | 
                - <string>需要您的位置用于在参加旅行团时,方便导游集合团员。如果不允许,将无法更加快捷的集合</string>  | 
            |
| 98 | 
                - <key>NSLocationWhenInUseUsageDescription</key>  | 
            |
| 99 | 
                - <string>App需要您的同意,才能访问您的位置</string>  | 
            |
| 100 | 88 | 
                <key>NSPhotoLibraryUsageDescription</key>  | 
            
| 101 | 89 | 
                <string>App需要您的同意,才能进行查看相册</string>  | 
            
| 90 | 
                + <key>NSPhotoLibraryAddUsageDescription</key>  | 
            |
| 91 | 
                + <string>cc</string>  | 
            |
| 102 | 92 | 
                <key>UILaunchStoryboardName</key>  | 
            
| 103 | 93 | 
                <string>LaunchScreen</string>  | 
            
| 104 | 94 | 
                <key>UIRequiredDeviceCapabilities</key>  | 
            
| 105 | 95 | 
                <array>  | 
            
| 106 | 96 | 
                <string>armv7</string>  | 
            
| 107 | 97 | 
                </array>  | 
            
| 98 | 
                + <key>UIStatusBarStyle</key>  | 
            |
| 99 | 
                + <string>UIStatusBarStyleLightContent</string>  | 
            |
| 108 | 100 | 
                <key>UISupportedInterfaceOrientations</key>  | 
            
| 109 | 101 | 
                <array>  | 
            
| 110 | 102 | 
                <string>UIInterfaceOrientationPortrait</string>  | 
            
| 111 | 103 | 
                </array>  | 
            
| 104 | 
                + <key>UIViewControllerBasedStatusBarAppearance</key>  | 
            |
| 105 | 
                + <true/>  | 
            |
| 112 | 106 | 
                <key>sina.com.cn</key>  | 
            
| 113 | 107 | 
                <dict>  | 
            
| 114 | 108 | 
                <key>NSExceptionMinimumTLSVersion</key>  | 
            
                @@ -10,18 +10,18 @@ import Foundation  | 
            ||
| 10 | 10 | 
                import ObjectMapper  | 
            
| 11 | 11 | 
                 | 
            
| 12 | 12 | 
                 public struct GroupDetailItem {
               | 
            
| 13 | 
                - var group = GroupItem(json: [:])  | 
            |
| 14 | 
                - var users: [GroupMemberItem] = []  | 
            |
| 15 | 
                - var group_id: String = ""  | 
            |
| 13 | 
                + public var group = GroupItem(json: [:])  | 
            |
| 14 | 
                + public var users: [GroupMemberItem] = []  | 
            |
| 15 | 
                + public var group_id: String = ""  | 
            |
| 16 | 16 | 
                 | 
            
| 17 | 
                -    init(json: [String: AnyObject]) {
               | 
            |
| 17 | 
                +    public init (json: [String: AnyObject]) {
               | 
            |
| 18 | 18 | 
                self.init(map: Map(mappingType: .fromJSON, JSON: json))  | 
            
| 19 | 19 | 
                }  | 
            
| 20 | 20 | 
                }  | 
            
| 21 | 21 | 
                 | 
            
| 22 | 22 | 
                 extension GroupDetailItem: Mappable {
               | 
            
| 23 | 23 | 
                     mutating public func mapping(map: Map) {
               | 
            
| 24 | 
                - users <- map["users"]  | 
            |
| 24 | 
                + users <- map["users.passed"]  | 
            |
| 25 | 25 | 
                group_id <- map["group_id"]  | 
            
| 26 | 26 | 
                group <- map["group"]  | 
            
| 27 | 27 | 
                }  | 
            
                @@ -30,9 +30,3 @@ extension GroupDetailItem: Mappable {
               | 
            ||
| 30 | 30 | 
                mapping(map: map)  | 
            
| 31 | 31 | 
                }  | 
            
| 32 | 32 | 
                }  | 
            
| 33 | 
                -  | 
            |
| 34 | 
                -extension GroupDetailItem: Equatable {
               | 
            |
| 35 | 
                -    public static func == (lhs: GroupDetailItem, rhs: GroupDetailItem) -> Bool {
               | 
            |
| 36 | 
                - return lhs.group_id == rhs.group_id  | 
            |
| 37 | 
                - }  | 
            |
| 38 | 
                -}  | 
            
                @@ -8,6 +8,7 @@  | 
            ||
| 8 | 8 | 
                 | 
            
| 9 | 9 | 
                import Foundation  | 
            
| 10 | 10 | 
                import ObjectMapper  | 
            
| 11 | 
                +import RxDataSources  | 
            |
| 11 | 12 | 
                 | 
            
| 12 | 13 | 
                 public struct GroupMemberItem {
               | 
            
| 13 | 14 | 
                 | 
            
                @@ -16,7 +17,7 @@ public struct GroupMemberItem {
               | 
            ||
| 16 | 17 | 
                public var nickname: String = ""  | 
            
| 17 | 18 | 
                public var admin: Bool = false  | 
            
| 18 | 19 | 
                 | 
            
| 19 | 
                -    init(json: [String: AnyObject]) {
               | 
            |
| 20 | 
                +    public init(json: [String: AnyObject]) {
               | 
            |
| 20 | 21 | 
                self.init(map: Map(mappingType: .fromJSON, JSON: json))  | 
            
| 21 | 22 | 
                }  | 
            
| 22 | 23 | 
                }  | 
            
                @@ -34,4 +35,11 @@ extension GroupMemberItem: Mappable {
               | 
            ||
| 34 | 35 | 
                }  | 
            
| 35 | 36 | 
                }  | 
            
| 36 | 37 | 
                 | 
            
| 37 | 
                -  | 
            |
| 38 | 
                +extension GroupMemberItem: IdentifiableType, Equatable {
               | 
            |
| 39 | 
                + public typealias Identity = String  | 
            |
| 40 | 
                +    public var identity: String { return user_id }
               | 
            |
| 41 | 
                +  | 
            |
| 42 | 
                +    public static func == (lhs: GroupMemberItem, rhs: GroupMemberItem) -> Bool {
               | 
            |
| 43 | 
                + return lhs.user_id == rhs.user_id  | 
            |
| 44 | 
                + }  | 
            |
| 45 | 
                +}  | 
            
                @@ -17,9 +17,10 @@ public enum MessageType: String {
               | 
            ||
| 17 | 17 | 
                 | 
            
| 18 | 18 | 
                 public struct MessageItem: JSONCode {
               | 
            
| 19 | 19 | 
                public var msg_unread_num = 0  | 
            
| 20 | 
                - public var msg_type_desc = ""  | 
            |
| 21 | 20 | 
                public var msg_type = MessageType.system  | 
            
| 22 | 
                - public var msg_avatar = ""  | 
            |
| 21 | 
                +  | 
            |
| 22 | 
                + var msg_type_desc = ""  | 
            |
| 23 | 
                + var msg_avatar = ""  | 
            |
| 23 | 24 | 
                 | 
            
| 24 | 25 | 
                     init(json: [String: AnyObject]) {
               | 
            
| 25 | 26 | 
                self.init(map: Map(mappingType: .fromJSON, JSON: json))  | 
            
                @@ -20,7 +20,6 @@ public struct MessageListItem: JSONCode {
               | 
            ||
| 20 | 20 | 
                public var group_photo_info = PhotoItem(json: [:])  | 
            
| 21 | 21 | 
                 | 
            
| 22 | 22 | 
                var read: Bool = false  | 
            
| 23 | 
                - public var title: String = ""  | 
            |
| 24 | 23 | 
                public var created_at: Date?  | 
            
| 25 | 24 | 
                 | 
            
| 26 | 25 | 
                var pk = 0  | 
            
                @@ -45,7 +44,6 @@ extension MessageListItem: Mappable {
               | 
            ||
| 45 | 44 | 
                content <- map["content"]  | 
            
| 46 | 45 | 
                pk <- map["pk"]  | 
            
| 47 | 46 | 
                read <- map["read"]  | 
            
| 48 | 
                - title <- map["title"]  | 
            |
| 49 | 47 | 
                from_avatar <- map["from_avatar"]  | 
            
| 50 | 48 | 
                from_nickname <- map["from_nickname"]  | 
            
| 51 | 49 | 
                from_uid <- map["from_uid"]  | 
            
                @@ -8,8 +8,9 @@  | 
            ||
| 8 | 8 | 
                 | 
            
| 9 | 9 | 
                import Foundation  | 
            
| 10 | 10 | 
                import ObjectMapper  | 
            
| 11 | 
                +import RxDataSources  | 
            |
| 11 | 12 | 
                 | 
            
| 12 | 
                -public struct PhotoCommentItem {
               | 
            |
| 13 | 
                +public struct PhotoCommentItem: JSONCode {
               | 
            |
| 13 | 14 | 
                 | 
            
| 14 | 15 | 
                public var avatar: String = ""  | 
            
| 15 | 16 | 
                public var comment: String = ""  | 
            
                @@ -37,3 +38,13 @@ extension PhotoCommentItem: Mappable {
               | 
            ||
| 37 | 38 | 
                mapping(map: map)  | 
            
| 38 | 39 | 
                }  | 
            
| 39 | 40 | 
                }  | 
            
| 41 | 
                +  | 
            |
| 42 | 
                +extension PhotoCommentItem: IdentifiableType, Equatable {
               | 
            |
| 43 | 
                + public typealias Identity = String  | 
            |
| 44 | 
                +    public var identity: String { return user_id + comment }
               | 
            |
| 45 | 
                +  | 
            |
| 46 | 
                +    public static func == (lhs: PhotoCommentItem, rhs: PhotoCommentItem) -> Bool {
               | 
            |
| 47 | 
                + return lhs.user_id == rhs.user_id && lhs.comment == rhs.comment  | 
            |
| 48 | 
                + }  | 
            |
| 49 | 
                +}  | 
            |
| 50 | 
                +  | 
            
                @@ -1,5 +1,5 @@  | 
            ||
| 1 | 1 | 
                //  | 
            
| 2 | 
                -// ThumbupUserItem.swift  | 
            |
| 2 | 
                +// PhotoThumbupUserItem.swift  | 
            |
| 3 | 3 | 
                // PaiaiDataKit  | 
            
| 4 | 4 | 
                //  | 
            
| 5 | 5 | 
                // Created by ffib on 2018/12/25.  | 
            
                @@ -8,8 +8,9 @@  | 
            ||
| 8 | 8 | 
                 | 
            
| 9 | 9 | 
                import Foundation  | 
            
| 10 | 10 | 
                import ObjectMapper  | 
            
| 11 | 
                +import RxDataSources  | 
            |
| 11 | 12 | 
                 | 
            
| 12 | 
                -public struct ThumbupUserItem {
               | 
            |
| 13 | 
                +public struct PhotoThumbupUserItem: JSONCode {
               | 
            |
| 13 | 14 | 
                public var avatar: String = ""  | 
            
| 14 | 15 | 
                public var user_id: String = ""  | 
            
| 15 | 16 | 
                public var nickname: String = ""  | 
            
                @@ -19,7 +20,7 @@ public struct ThumbupUserItem {
               | 
            ||
| 19 | 20 | 
                }  | 
            
| 20 | 21 | 
                }  | 
            
| 21 | 22 | 
                 | 
            
| 22 | 
                -extension ThumbupUserItem: Mappable {
               | 
            |
| 23 | 
                +extension PhotoThumbupUserItem: Mappable {
               | 
            |
| 23 | 24 | 
                     mutating public func mapping(map: Map) {
               | 
            
| 24 | 25 | 
                avatar <- map["avatar"]  | 
            
| 25 | 26 | 
                user_id <- map["user_id"]  | 
            
                @@ -30,3 +31,12 @@ extension ThumbupUserItem: Mappable {
               | 
            ||
| 30 | 31 | 
                mapping(map: map)  | 
            
| 31 | 32 | 
                }  | 
            
| 32 | 33 | 
                }  | 
            
| 34 | 
                +  | 
            |
| 35 | 
                +extension PhotoThumbupUserItem: IdentifiableType, Equatable {
               | 
            |
| 36 | 
                + public typealias Identity = String  | 
            |
| 37 | 
                +    public var identity: String { return user_id }
               | 
            |
| 38 | 
                +  | 
            |
| 39 | 
                +    public static func == (lhs: PhotoThumbupUserItem, rhs: PhotoThumbupUserItem) -> Bool {
               | 
            |
| 40 | 
                + return lhs.user_id == rhs.user_id  | 
            |
| 41 | 
                + }  | 
            |
| 42 | 
                +}  | 
            
                @@ -7,3 +7,21 @@  | 
            ||
| 7 | 7 | 
                //  | 
            
| 8 | 8 | 
                 | 
            
| 9 | 9 | 
                import Foundation  | 
            
| 10 | 
                +  | 
            |
| 11 | 
                +struct OriginData<DataItem: JSONCode> {
               | 
            |
| 12 | 
                + var status = 0  | 
            |
| 13 | 
                + var data: [DataItem] = []  | 
            |
| 14 | 
                +  | 
            |
| 15 | 
                +    init() {}
               | 
            |
| 16 | 
                +  | 
            |
| 17 | 
                +    init(json: JSON, dataField: String) {
               | 
            |
| 18 | 
                + guard let status = json["status"] as? Int,  | 
            |
| 19 | 
                +            let result = json[dataField] as? [[String: AnyObject]] else { return }
               | 
            |
| 20 | 
                + self.status = status  | 
            |
| 21 | 
                +        data = result.map { DataItem.init(json: $0) }
               | 
            |
| 22 | 
                + }  | 
            |
| 23 | 
                +  | 
            |
| 24 | 
                +    static func empty() -> OriginData {
               | 
            |
| 25 | 
                + return OriginData()  | 
            |
| 26 | 
                + }  | 
            |
| 27 | 
                +}  | 
            
                @@ -1,5 +1,5 @@  | 
            ||
| 1 | 1 | 
                //  | 
            
| 2 | 
                -// HomePhotoRepository.swift  | 
            |
| 2 | 
                +// HomeRepository.swift  | 
            |
| 3 | 3 | 
                // PaiAi  | 
            
| 4 | 4 | 
                //  | 
            
| 5 | 5 | 
                // Created by FFIB on 16/3/31.  | 
            
                @@ -10,9 +10,9 @@ import Foundation  | 
            ||
| 10 | 10 | 
                import RxCocoa  | 
            
| 11 | 11 | 
                import RxSwift  | 
            
| 12 | 12 | 
                 | 
            
| 13 | 
                -struct HomePhotoRepository: PhotoRepository {
               | 
            |
| 13 | 
                +struct HomeRepository: PhotoRepository {
               | 
            |
| 14 | 14 | 
                 | 
            
| 15 | 
                - var homeRemoteAPI = HomePhotoRemoteAPI()  | 
            |
| 15 | 
                + var homeRemoteAPI = HomeRemoteAPI()  | 
            |
| 16 | 16 | 
                 | 
            
| 17 | 17 | 
                     func load(page: Int) -> Single<NetworkArrayData<PhotoItem>> {
               | 
            
| 18 | 18 | 
                return homeRemoteAPI.loadContent(page: page)  | 
            
                @@ -9,11 +9,66 @@  | 
            ||
| 9 | 9 | 
                import Foundation  | 
            
| 10 | 10 | 
                import RxSwift  | 
            
| 11 | 11 | 
                 | 
            
| 12 | 
                +public protocol MessageInteractionModel {
               | 
            |
| 13 | 
                +    var path: Interfaces { get }
               | 
            |
| 14 | 
                +    var removePath: Interfaces { get }
               | 
            |
| 15 | 
                +    var readPath: Interfaces { get }
               | 
            |
| 16 | 
                +    var title: String { get }
               | 
            |
| 17 | 
                +}  | 
            |
| 18 | 
                +  | 
            |
| 19 | 
                +extension MessageType {
               | 
            |
| 20 | 
                +  | 
            |
| 21 | 
                +    public var model: MessageInteractionModel {
               | 
            |
| 22 | 
                +        switch self {
               | 
            |
| 23 | 
                + case .thumbup: return MessagethumbupInteractionModel()  | 
            |
| 24 | 
                + case .comment: return MessageCommentInteractionModel()  | 
            |
| 25 | 
                + case .system: return MessageSystemInteractionModel()  | 
            |
| 26 | 
                + }  | 
            |
| 27 | 
                + }  | 
            |
| 28 | 
                +  | 
            |
| 29 | 
                +    fileprivate struct MessagethumbupInteractionModel: MessageInteractionModel {
               | 
            |
| 30 | 
                +        var path: Interfaces { return .mesThumbupList}
               | 
            |
| 31 | 
                +        var removePath: Interfaces { return .mesThumbupClear }
               | 
            |
| 32 | 
                +        var readPath: Interfaces { return .mesThumbupRead }
               | 
            |
| 33 | 
                +        var title: String { return "赞" }
               | 
            |
| 34 | 
                + }  | 
            |
| 35 | 
                +  | 
            |
| 36 | 
                +    fileprivate struct MessageCommentInteractionModel: MessageInteractionModel {
               | 
            |
| 37 | 
                +        var path: Interfaces { return .mesCommentList}
               | 
            |
| 38 | 
                +        var removePath: Interfaces { return .mesCommentClear }
               | 
            |
| 39 | 
                +        var readPath: Interfaces { return .mesCommentRead }
               | 
            |
| 40 | 
                +        var title: String { return "评论" }
               | 
            |
| 41 | 
                + }  | 
            |
| 42 | 
                +  | 
            |
| 43 | 
                +    fileprivate struct MessageSystemInteractionModel: MessageInteractionModel {
               | 
            |
| 44 | 
                +        var path: Interfaces { return .mesSystemList}
               | 
            |
| 45 | 
                +        var removePath: Interfaces { return .mesSystemClear }
               | 
            |
| 46 | 
                +        var readPath: Interfaces { return .mesSystemRead }
               | 
            |
| 47 | 
                +        var title: String { return "系统消息" }
               | 
            |
| 48 | 
                + }  | 
            |
| 49 | 
                +}  | 
            |
| 50 | 
                +  | 
            |
| 12 | 51 | 
                 struct MessageRepository {
               | 
            
| 13 | 52 | 
                 | 
            
| 14 | 53 | 
                var messageRemoteAPI = MessageRemoteAPI()  | 
            
| 15 | 54 | 
                 | 
            
| 16 | 
                -    mutating func load() -> Single<[MessageItem]> {
               | 
            |
| 55 | 
                +    func loadContent() -> Single<[MessageItem]> {
               | 
            |
| 17 | 56 | 
                return messageRemoteAPI.loadContent()  | 
            
| 18 | 57 | 
                }  | 
            
| 58 | 
                +  | 
            |
| 59 | 
                +    func loadMessageList(_ type: MessageType, page: Int) -> Single<NetworkArrayData<MessageListItem>> {
               | 
            |
| 60 | 
                + return messageRemoteAPI.loadMessageList(type, page: page)  | 
            |
| 61 | 
                + }  | 
            |
| 62 | 
                +  | 
            |
| 63 | 
                +    func remove(_ type: MessageType, pk: Int) -> Completable {
               | 
            |
| 64 | 
                + return messageRemoteAPI.remove(type, pk: pk)  | 
            |
| 65 | 
                + }  | 
            |
| 66 | 
                +  | 
            |
| 67 | 
                +    func removeAll(_ type: MessageType) -> Completable {
               | 
            |
| 68 | 
                + return messageRemoteAPI.removeAll(type)  | 
            |
| 69 | 
                + }  | 
            |
| 70 | 
                +  | 
            |
| 71 | 
                +    func readed(_ type: MessageType) -> Completable {
               | 
            |
| 72 | 
                + return messageRemoteAPI.readed(type)  | 
            |
| 73 | 
                + }  | 
            |
| 19 | 74 | 
                }  | 
            
                @@ -1,240 +0,0 @@  | 
            ||
| 1 | 
                -//  | 
            |
| 2 | 
                -// MessageModel.swift  | 
            |
| 3 | 
                -// PaiAi  | 
            |
| 4 | 
                -//  | 
            |
| 5 | 
                -// Created by zhengjianfei on 16/4/7.  | 
            |
| 6 | 
                -// Copyright © 2016年 FFIB. All rights reserved.  | 
            |
| 7 | 
                -//  | 
            |
| 8 | 
                -  | 
            |
| 9 | 
                -import Foundation  | 
            |
| 10 | 
                -import ObjectMapper  | 
            |
| 11 | 
                -import RxCocoa  | 
            |
| 12 | 
                -import RxDataSources  | 
            |
| 13 | 
                -  | 
            |
| 14 | 
                -import Foundation  | 
            |
| 15 | 
                -import RxCocoa  | 
            |
| 16 | 
                -import RxSwift  | 
            |
| 17 | 
                -  | 
            |
| 18 | 
                -public protocol MessageRepositorable: Repositorable where Content == [GroupItem] {}
               | 
            |
| 19 | 
                -  | 
            |
| 20 | 
                -final public class MessageRepository: Resource {
               | 
            |
| 21 | 
                - fileprivate var items: BehaviorRelay<[GroupItem]>  | 
            |
| 22 | 
                - fileprivate var hasMore: Bool  | 
            |
| 23 | 
                - fileprivate var page: Int  | 
            |
| 24 | 
                - fileprivate var loadingSchedule: PublishSubject<Bool>  | 
            |
| 25 | 
                -  | 
            |
| 26 | 
                -    var path: Interfaces { return .groupList }
               | 
            |
| 27 | 
                -    #warning("admin_id 填充")
               | 
            |
| 28 | 
                - var parameter: Parameter = ["admin_id": ""]  | 
            |
| 29 | 
                - fileprivate var deleteResource: GroupDeleteResource  | 
            |
| 30 | 
                -  | 
            |
| 31 | 
                -  | 
            |
| 32 | 
                -    init() {
               | 
            |
| 33 | 
                - page = 1  | 
            |
| 34 | 
                - hasMore = true  | 
            |
| 35 | 
                - loadingSchedule = PublishSubject<Bool>()  | 
            |
| 36 | 
                - items = BehaviorRelay<[GroupItem]>(value: [])  | 
            |
| 37 | 
                - deleteResource = GroupDeleteResource()  | 
            |
| 38 | 
                - }  | 
            |
| 39 | 
                -}  | 
            |
| 40 | 
                -  | 
            |
| 41 | 
                -extension GroupRepository: Parsable {
               | 
            |
| 42 | 
                - typealias Model = [GroupItem]  | 
            |
| 43 | 
                -  | 
            |
| 44 | 
                -    func parse(_ json: JSON) -> [GroupItem]? {
               | 
            |
| 45 | 
                - guard let data = json["data"] as? [String: AnyObject],  | 
            |
| 46 | 
                - let messages = data["groups"] as? [[String: AnyObject]],  | 
            |
| 47 | 
                -            let left = data["left"] as? Int else { return nil }
               | 
            |
| 48 | 
                - hasMore = left > 0  | 
            |
| 49 | 
                -        return messages.map { return GroupItem(json: $0) }
               | 
            |
| 50 | 
                - }  | 
            |
| 51 | 
                -}  | 
            |
| 52 | 
                -  | 
            |
| 53 | 
                -extension GroupRepository: Gettable {
               | 
            |
| 54 | 
                -    public func loadContent(isRefresh: Bool) {
               | 
            |
| 55 | 
                -        guard hasMore else {
               | 
            |
| 56 | 
                - loadingSchedule.onNext(isRefresh)  | 
            |
| 57 | 
                - return  | 
            |
| 58 | 
                - }  | 
            |
| 59 | 
                -  | 
            |
| 60 | 
                - page = isRefresh ? 1 : page + 1  | 
            |
| 61 | 
                - parameter["page"] = page  | 
            |
| 62 | 
                -        let _ = NetworkApi.share.post(resource: self) { result in
               | 
            |
| 63 | 
                -  | 
            |
| 64 | 
                -            defer { self.loadingSchedule.onNext(isRefresh) }
               | 
            |
| 65 | 
                -  | 
            |
| 66 | 
                -            guard case let .success(items) = result else {
               | 
            |
| 67 | 
                - return  | 
            |
| 68 | 
                - }  | 
            |
| 69 | 
                -  | 
            |
| 70 | 
                -            if isRefresh {
               | 
            |
| 71 | 
                - self.items.accept(items)  | 
            |
| 72 | 
                -            } else {
               | 
            |
| 73 | 
                - self.items.accept(self.items.value + items)  | 
            |
| 74 | 
                - }  | 
            |
| 75 | 
                - }  | 
            |
| 76 | 
                - }  | 
            |
| 77 | 
                -}  | 
            |
| 78 | 
                -  | 
            |
| 79 | 
                -extension GroupRepository: Deletable {
               | 
            |
| 80 | 
                -    func remove(of index: Int) {
               | 
            |
| 81 | 
                - let item = items.value[index]  | 
            |
| 82 | 
                - deleteResource.parameter["group_id"] = item.group_id  | 
            |
| 83 | 
                -        NetworkApi.share.post(resource: deleteResource) { [weak self] result in
               | 
            |
| 84 | 
                -            guard case let .success(statusModel) = result else { return }
               | 
            |
| 85 | 
                -            guard let `self` = self else { return }
               | 
            |
| 86 | 
                -            if statusModel.status == 200 {
               | 
            |
| 87 | 
                - var values = self.items.value  | 
            |
| 88 | 
                - values.remove(at: index)  | 
            |
| 89 | 
                - self.items.accept(values)  | 
            |
| 90 | 
                -            } else if statusModel.status == 402010 {
               | 
            |
| 91 | 
                -                #warning("无权限")
               | 
            |
| 92 | 
                -            } else if statusModel.status == 402099 {
               | 
            |
| 93 | 
                -                #warning("无权限")
               | 
            |
| 94 | 
                - }  | 
            |
| 95 | 
                - }  | 
            |
| 96 | 
                - }  | 
            |
| 97 | 
                -}  | 
            |
| 98 | 
                -  | 
            |
| 99 | 
                -extension GroupRepository: GroupRepositorable {
               | 
            |
| 100 | 
                -    public var content: Observable<[GroupItem]> {
               | 
            |
| 101 | 
                - return items.asObservable()  | 
            |
| 102 | 
                -            .flatMap { currentItems in
               | 
            |
| 103 | 
                - Observable.just(currentItems)  | 
            |
| 104 | 
                - .distinctUntilChanged()  | 
            |
| 105 | 
                - }.share()  | 
            |
| 106 | 
                - }  | 
            |
| 107 | 
                -  | 
            |
| 108 | 
                -    public var loadingObserver: Observable<Bool> {
               | 
            |
| 109 | 
                - return loadingSchedule.asObserver()  | 
            |
| 110 | 
                -            .flatMap { current in
               | 
            |
| 111 | 
                - Observable.just(current)  | 
            |
| 112 | 
                - }.share()  | 
            |
| 113 | 
                - }  | 
            |
| 114 | 
                -}  | 
            |
| 115 | 
                -  | 
            |
| 116 | 
                -  | 
            |
| 117 | 
                -protocol MessageInteractionModel {
               | 
            |
| 118 | 
                -    var path: Interfaces { get }
               | 
            |
| 119 | 
                -    var deletePath: Interfaces { get }
               | 
            |
| 120 | 
                -    var readPath: Interfaces { get }
               | 
            |
| 121 | 
                -    var title: String { get }
               | 
            |
| 122 | 
                -}  | 
            |
| 123 | 
                -  | 
            |
| 124 | 
                -  | 
            |
| 125 | 
                -public enum MessageType: String {
               | 
            |
| 126 | 
                - case zan = "zan"  | 
            |
| 127 | 
                - case comment = "comment"  | 
            |
| 128 | 
                - case system = "system"  | 
            |
| 129 | 
                -  | 
            |
| 130 | 
                -    fileprivate var messageInteractionModel: MessageInteractionModel {
               | 
            |
| 131 | 
                -        switch self {
               | 
            |
| 132 | 
                - case .zan: return MessageZanInteractionModel()  | 
            |
| 133 | 
                - case .comment: return MessageCommentInteractionModel()  | 
            |
| 134 | 
                - case .system: return MessageSystemInteractionModel()  | 
            |
| 135 | 
                - }  | 
            |
| 136 | 
                - }  | 
            |
| 137 | 
                -  | 
            |
| 138 | 
                -    fileprivate struct MessageZanInteractionModel: MessageInteractionModel {
               | 
            |
| 139 | 
                -        var path: Interfaces { return .mesThumbupList}
               | 
            |
| 140 | 
                -        var deletePath: Interfaces { return .mesThumbupClear }
               | 
            |
| 141 | 
                -        var readPath: Interfaces { return .mesThumbupRead }
               | 
            |
| 142 | 
                -        var title: String { return "赞" }
               | 
            |
| 143 | 
                - }  | 
            |
| 144 | 
                -  | 
            |
| 145 | 
                -    fileprivate struct MessageCommentInteractionModel: MessageInteractionModel {
               | 
            |
| 146 | 
                -        var path: Interfaces { return .mesCommentList}
               | 
            |
| 147 | 
                -        var deletePath: Interfaces { return .mesCommentClear }
               | 
            |
| 148 | 
                -        var readPath: Interfaces { return .mesCommentRead }
               | 
            |
| 149 | 
                -        var title: String { return "评论" }
               | 
            |
| 150 | 
                - }  | 
            |
| 151 | 
                -  | 
            |
| 152 | 
                -    fileprivate struct MessageSystemInteractionModel: MessageInteractionModel {
               | 
            |
| 153 | 
                -        var path: Interfaces { return .mesSystemList}
               | 
            |
| 154 | 
                -        var deletePath: Interfaces { return .mesSystemClear }
               | 
            |
| 155 | 
                -        var readPath: Interfaces { return .mesSystemRead }
               | 
            |
| 156 | 
                -        var title: String { return "系统消息" }
               | 
            |
| 157 | 
                - }  | 
            |
| 158 | 
                -}  | 
            |
| 159 | 
                -  | 
            |
| 160 | 
                -  | 
            |
| 161 | 
                -  | 
            |
| 162 | 
                -final class MessageModel {
               | 
            |
| 163 | 
                - private(set) var items: BehaviorRelay<[MessageItem]>  | 
            |
| 164 | 
                - private var hasMore = true  | 
            |
| 165 | 
                - private var page = 1  | 
            |
| 166 | 
                - private var contentsResource: Resource<[MessageItem]>?  | 
            |
| 167 | 
                - private var deleteItemResource: Resource<StatusModel>?  | 
            |
| 168 | 
                - private var readMessageResource: Resource<StatusModel>?  | 
            |
| 169 | 
                -  | 
            |
| 170 | 
                -  | 
            |
| 171 | 
                -    init(type: MessageType) {
               | 
            |
| 172 | 
                - items = BehaviorRelay<[MessageItem]>(value: [])  | 
            |
| 173 | 
                -  | 
            |
| 174 | 
                - contentsResource = Resource(url: type.messageInteractionModel.path,  | 
            |
| 175 | 
                - param: ["user_id": SharedUserInfo.userId as AnyObject],  | 
            |
| 176 | 
                - parse: parse)  | 
            |
| 177 | 
                - deleteItemResource = Resource(url: type.messageInteractionModel.deletePath,  | 
            |
| 178 | 
                - param: ["user_id": SharedUserInfo.userId as AnyObject],  | 
            |
| 179 | 
                - parse: parseStatus)  | 
            |
| 180 | 
                - readMessageResource = Resource(url: type.messageInteractionModel.readPath,  | 
            |
| 181 | 
                - param: ["user_id": SharedUserInfo.userId as AnyObject,  | 
            |
| 182 | 
                - "all": "true" as AnyObject],  | 
            |
| 183 | 
                - parse: parseStatus)  | 
            |
| 184 | 
                - }  | 
            |
| 185 | 
                -  | 
            |
| 186 | 
                -    private func parse(json: [String: AnyObject]) -> [MessageItem]? {
               | 
            |
| 187 | 
                - guard let data = json["data"],  | 
            |
| 188 | 
                - let messages = data["messages"] as? [[String: AnyObject]],  | 
            |
| 189 | 
                -            let left = data["left"] as? Int else { return nil }
               | 
            |
| 190 | 
                - hasMore = left > 0  | 
            |
| 191 | 
                -        return messages.map { return MessageItem(json: $0) }
               | 
            |
| 192 | 
                - }  | 
            |
| 193 | 
                -  | 
            |
| 194 | 
                -    private func parseStatus(json: [String: AnyObject]) -> StatusModel? {
               | 
            |
| 195 | 
                - return StatusModel(json: json)  | 
            |
| 196 | 
                - }  | 
            |
| 197 | 
                -  | 
            |
| 198 | 
                -    func loadContents(isRefresh: Bool) {
               | 
            |
| 199 | 
                -        guard hasMore else { return }
               | 
            |
| 200 | 
                - page = isRefresh ? 1 : page + 1  | 
            |
| 201 | 
                - contentsResource!.parameter["page"] = page as AnyObject  | 
            |
| 202 | 
                -        NetworkApi.share.post(resource: contentsResource!) { [weak self] result in
               | 
            |
| 203 | 
                -            guard case let .success(messageItems) = result else { return }
               | 
            |
| 204 | 
                -            guard let `self` = self else { return }
               | 
            |
| 205 | 
                -            if isRefresh {
               | 
            |
| 206 | 
                - self.items.accept(messageItems)  | 
            |
| 207 | 
                -            } else {
               | 
            |
| 208 | 
                - self.items.accept(self.items.value + messageItems)  | 
            |
| 209 | 
                - }  | 
            |
| 210 | 
                -  | 
            |
| 211 | 
                - }  | 
            |
| 212 | 
                - }  | 
            |
| 213 | 
                -  | 
            |
| 214 | 
                -    func remove(_ item: MessageItem) {
               | 
            |
| 215 | 
                -        guard let index = items.value.index(where: { $0 == item }) else { return }
               | 
            |
| 216 | 
                - deleteItemResource!.parameter["pk"] = items.value[index].pk as AnyObject  | 
            |
| 217 | 
                -        NetworkApi.share.post(resource: deleteItemResource!) { [weak self] result in
               | 
            |
| 218 | 
                -            guard case .success(_) = result else { return }
               | 
            |
| 219 | 
                -            guard let `self` = self else { return }
               | 
            |
| 220 | 
                -  | 
            |
| 221 | 
                - var values = self.items.value  | 
            |
| 222 | 
                - values.remove(at: index)  | 
            |
| 223 | 
                - self.items.accept(values)  | 
            |
| 224 | 
                - }  | 
            |
| 225 | 
                - }  | 
            |
| 226 | 
                -  | 
            |
| 227 | 
                -    func removeAll(_ completion:@escaping () -> ()) {
               | 
            |
| 228 | 
                - deleteItemResource!.parameter["all"] = true as AnyObject  | 
            |
| 229 | 
                -        NetworkApi.share.post(resource: deleteItemResource!) { [weak self] result in
               | 
            |
| 230 | 
                -            guard case .success(_) = result else { return }
               | 
            |
| 231 | 
                -            guard let `self` = self else { return }
               | 
            |
| 232 | 
                - self.items.accept([])  | 
            |
| 233 | 
                - completion()  | 
            |
| 234 | 
                - }  | 
            |
| 235 | 
                - }  | 
            |
| 236 | 
                -  | 
            |
| 237 | 
                -    func readMessage() {
               | 
            |
| 238 | 
                -        NetworkApi.share.post(resource: readMessageResource!, completion: {_ in })
               | 
            |
| 239 | 
                - }  | 
            |
| 240 | 
                -}  | 
            
                @@ -1,52 +0,0 @@  | 
            ||
| 1 | 
                -//  | 
            |
| 2 | 
                -// OrderModel.swift  | 
            |
| 3 | 
                -// PaiAi  | 
            |
| 4 | 
                -//  | 
            |
| 5 | 
                -// Created by zhengjianfei on 16/4/7.  | 
            |
| 6 | 
                -// Copyright © 2016年 FFIB. All rights reserved.  | 
            |
| 7 | 
                -//  | 
            |
| 8 | 
                -  | 
            |
| 9 | 
                -import Foundation  | 
            |
| 10 | 
                -import RxSwift  | 
            |
| 11 | 
                -import RxCocoa  | 
            |
| 12 | 
                -  | 
            |
| 13 | 
                -final class OrderModel {
               | 
            |
| 14 | 
                -  | 
            |
| 15 | 
                -}  | 
            |
| 16 | 
                -  | 
            |
| 17 | 
                -final class OrderModel {
               | 
            |
| 18 | 
                - private(set) var items: BehaviorRelay<[OrderItem]>  | 
            |
| 19 | 
                - private var hasMore = true  | 
            |
| 20 | 
                - private var page = 1  | 
            |
| 21 | 
                - private var contentsResource: Resource<[OrderItem]>?  | 
            |
| 22 | 
                -  | 
            |
| 23 | 
                -    init() {
               | 
            |
| 24 | 
                - items = BehaviorRelay<[OrderItem]>(value: [])  | 
            |
| 25 | 
                - contentsResource = Resource(url: .orderList,  | 
            |
| 26 | 
                - param: ["user_id": SharedUserInfo.userId as AnyObject],  | 
            |
| 27 | 
                - parse: parse)  | 
            |
| 28 | 
                - }  | 
            |
| 29 | 
                -  | 
            |
| 30 | 
                -    private func parse(json: [String: AnyObject]) -> [OrderItem]? {
               | 
            |
| 31 | 
                - guard let data = json["data"],  | 
            |
| 32 | 
                - let orders = data["orders"] as? [[String: AnyObject]],  | 
            |
| 33 | 
                -            let left = data["left"] as? Int else { return nil }
               | 
            |
| 34 | 
                - hasMore = left > 0  | 
            |
| 35 | 
                -        return orders.map { return OrderItem(json: $0) }
               | 
            |
| 36 | 
                - }  | 
            |
| 37 | 
                -  | 
            |
| 38 | 
                -    func loadContents(isRefresh: Bool) {
               | 
            |
| 39 | 
                -        guard hasMore else { return }
               | 
            |
| 40 | 
                - page = isRefresh ? 1 : page + 1  | 
            |
| 41 | 
                - contentsResource?.parameter["page"] = page as AnyObject  | 
            |
| 42 | 
                -        NetworkApi.share.post(resource: contentsResource!) { [weak self] result in
               | 
            |
| 43 | 
                -            guard case let .success(orderItems) = result else { return }
               | 
            |
| 44 | 
                -            guard let `self` = self else { return }
               | 
            |
| 45 | 
                -            if isRefresh {
               | 
            |
| 46 | 
                - self.items.accept(orderItems)  | 
            |
| 47 | 
                -            } else {
               | 
            |
| 48 | 
                - self.items.accept(orderItems + self.items.value)  | 
            |
| 49 | 
                - }  | 
            |
| 50 | 
                - }  | 
            |
| 51 | 
                - }  | 
            |
| 52 | 
                -}  | 
            
                @@ -1,140 +0,0 @@  | 
            ||
| 1 | 
                -//  | 
            |
| 2 | 
                -// OrderRepository.swift  | 
            |
| 3 | 
                -// PaiAi  | 
            |
| 4 | 
                -//  | 
            |
| 5 | 
                -// Created by zhengjianfei on 16/4/7.  | 
            |
| 6 | 
                -// Copyright © 2016年 FFIB. All rights reserved.  | 
            |
| 7 | 
                -//  | 
            |
| 8 | 
                -  | 
            |
| 9 | 
                -import Foundation  | 
            |
| 10 | 
                -import RxSwift  | 
            |
| 11 | 
                -import RxCocoa  | 
            |
| 12 | 
                -  | 
            |
| 13 | 
                -public protocol OrderRepositorable: Repositorable where Content == OrderItem {}
               | 
            |
| 14 | 
                -  | 
            |
| 15 | 
                -final public class OrderModelRepository {
               | 
            |
| 16 | 
                - fileprivate var items: BehaviorRelay<[OrderItem]>  | 
            |
| 17 | 
                - fileprivate var hasMore = true  | 
            |
| 18 | 
                - fileprivate var page = 1  | 
            |
| 19 | 
                - fileprivate var contentsResource: Resource<[OrderItem]>?  | 
            |
| 20 | 
                -}  | 
            |
| 21 | 
                -  | 
            |
| 22 | 
                -public protocol OrderRepository: Repositorable where Content == [PhotoItem] {}
               | 
            |
| 23 | 
                -  | 
            |
| 24 | 
                -final public class HomePhotoRepository: Resource {
               | 
            |
| 25 | 
                - fileprivate var items: BehaviorRelay<[PhotoItem]>  | 
            |
| 26 | 
                - fileprivate var hasMore: Bool  | 
            |
| 27 | 
                - fileprivate var page: Int  | 
            |
| 28 | 
                - fileprivate var loadingSchedule: PublishSubject<Bool>  | 
            |
| 29 | 
                -  | 
            |
| 30 | 
                -    var path: Interfaces { return .home }
               | 
            |
| 31 | 
                -    #warning("user_id 填充")
               | 
            |
| 32 | 
                - var parameter: Parameter = ["user_id": ""]  | 
            |
| 33 | 
                -  | 
            |
| 34 | 
                -    init() {
               | 
            |
| 35 | 
                - page = 1  | 
            |
| 36 | 
                - hasMore = true  | 
            |
| 37 | 
                - loadingSchedule = PublishSubject<Bool>()  | 
            |
| 38 | 
                - items = BehaviorRelay<[PhotoItem]>(value: [])  | 
            |
| 39 | 
                - }  | 
            |
| 40 | 
                -}  | 
            |
| 41 | 
                -  | 
            |
| 42 | 
                -extension HomePhotoRepository: Parsable {
               | 
            |
| 43 | 
                - typealias Model = [PhotoItem]  | 
            |
| 44 | 
                -  | 
            |
| 45 | 
                -    func parse(_ json: JSON) -> [PhotoItem]? {
               | 
            |
| 46 | 
                - guard let data = json["data"] as? [String: AnyObject],  | 
            |
| 47 | 
                - let left = data["left"] as? Int,  | 
            |
| 48 | 
                -            let photos = data["photos"] as? [[String: AnyObject]] else {
               | 
            |
| 49 | 
                - return nil  | 
            |
| 50 | 
                - }  | 
            |
| 51 | 
                - hasMore = left > 0  | 
            |
| 52 | 
                -        return photos.map { return PhotoItem(json: $0) }
               | 
            |
| 53 | 
                - }  | 
            |
| 54 | 
                -}  | 
            |
| 55 | 
                -  | 
            |
| 56 | 
                -extension HomePhotoRepository: Gettable {
               | 
            |
| 57 | 
                -    public func loadContent(isRefresh: Bool) {
               | 
            |
| 58 | 
                -        guard hasMore else {
               | 
            |
| 59 | 
                - loadingSchedule.onNext(isRefresh)  | 
            |
| 60 | 
                - return  | 
            |
| 61 | 
                - }  | 
            |
| 62 | 
                -  | 
            |
| 63 | 
                - page = isRefresh ? 1 : page + 1  | 
            |
| 64 | 
                - parameter["page"] = page  | 
            |
| 65 | 
                -        let _ = NetworkApi.share.post(resource: self) { result in
               | 
            |
| 66 | 
                -  | 
            |
| 67 | 
                -            defer { self.loadingSchedule.onNext(isRefresh) }
               | 
            |
| 68 | 
                -  | 
            |
| 69 | 
                -            guard case let .success(photoItems) = result else {
               | 
            |
| 70 | 
                - return  | 
            |
| 71 | 
                - }  | 
            |
| 72 | 
                -  | 
            |
| 73 | 
                -            if isRefresh {
               | 
            |
| 74 | 
                - self.items.accept(photoItems)  | 
            |
| 75 | 
                -            } else {
               | 
            |
| 76 | 
                - self.items.accept(self.items.value + photoItems)  | 
            |
| 77 | 
                - }  | 
            |
| 78 | 
                - }  | 
            |
| 79 | 
                - }  | 
            |
| 80 | 
                -}  | 
            |
| 81 | 
                -  | 
            |
| 82 | 
                -extension HomePhotoRepository: HomePhotoRepositorable {
               | 
            |
| 83 | 
                -    public var content: Observable<[PhotoItem]> {
               | 
            |
| 84 | 
                - return items.asObservable()  | 
            |
| 85 | 
                -            .flatMap { currentItems in
               | 
            |
| 86 | 
                - Observable.just(currentItems)  | 
            |
| 87 | 
                - .distinctUntilChanged()  | 
            |
| 88 | 
                - }.share()  | 
            |
| 89 | 
                - }  | 
            |
| 90 | 
                -  | 
            |
| 91 | 
                -    public var loadingObserver: Observable<Bool> {
               | 
            |
| 92 | 
                - return loadingSchedule.asObserver()  | 
            |
| 93 | 
                -            .flatMap { current in
               | 
            |
| 94 | 
                - Observable.just(current)  | 
            |
| 95 | 
                - }.share()  | 
            |
| 96 | 
                - }  | 
            |
| 97 | 
                -}  | 
            |
| 98 | 
                -  | 
            |
| 99 | 
                -extension HomePhotoRepository: Layoutable {
               | 
            |
| 100 | 
                -    public func layoutSizeForIndex(_ index: Int) -> CGSize {
               | 
            |
| 101 | 
                - let h = items.value[index].photo_thumbnail_h  | 
            |
| 102 | 
                - let w = items.value[index].photo_thumbnail_w  | 
            |
| 103 | 
                - return CGSize(width: w, height: h)  | 
            |
| 104 | 
                - }  | 
            |
| 105 | 
                -}  | 
            |
| 106 | 
                -  | 
            |
| 107 | 
                -  | 
            |
| 108 | 
                -final class OrderModel {
               | 
            |
| 109 | 
                -  | 
            |
| 110 | 
                -  | 
            |
| 111 | 
                -    init() {
               | 
            |
| 112 | 
                - items = BehaviorRelay<[OrderItem]>(value: [])  | 
            |
| 113 | 
                - contentsResource = Resource(url: .orderList,  | 
            |
| 114 | 
                - param: ["user_id": SharedUserInfo.userId as AnyObject],  | 
            |
| 115 | 
                - parse: parse)  | 
            |
| 116 | 
                - }  | 
            |
| 117 | 
                -  | 
            |
| 118 | 
                -    private func parse(json: [String: AnyObject]) -> [OrderItem]? {
               | 
            |
| 119 | 
                - guard let data = json["data"],  | 
            |
| 120 | 
                - let orders = data["orders"] as? [[String: AnyObject]],  | 
            |
| 121 | 
                -            let left = data["left"] as? Int else { return nil }
               | 
            |
| 122 | 
                - hasMore = left > 0  | 
            |
| 123 | 
                -        return orders.map { return OrderItem(json: $0) }
               | 
            |
| 124 | 
                - }  | 
            |
| 125 | 
                -  | 
            |
| 126 | 
                -    func loadContents(isRefresh: Bool) {
               | 
            |
| 127 | 
                -        guard hasMore else { return }
               | 
            |
| 128 | 
                - page = isRefresh ? 1 : page + 1  | 
            |
| 129 | 
                - contentsResource?.parameter["page"] = page as AnyObject  | 
            |
| 130 | 
                -        NetworkApi.share.post(resource: contentsResource!) { [weak self] result in
               | 
            |
| 131 | 
                -            guard case let .success(orderItems) = result else { return }
               | 
            |
| 132 | 
                -            guard let `self` = self else { return }
               | 
            |
| 133 | 
                -            if isRefresh {
               | 
            |
| 134 | 
                - self.items.accept(orderItems)  | 
            |
| 135 | 
                -            } else {
               | 
            |
| 136 | 
                - self.items.accept(orderItems + self.items.value)  | 
            |
| 137 | 
                - }  | 
            |
| 138 | 
                - }  | 
            |
| 139 | 
                - }  | 
            |
| 140 | 
                -}  | 
            
                @@ -28,12 +28,10 @@ extension UserDefaults {
               | 
            ||
| 28 | 28 | 
                }  | 
            
| 29 | 29 | 
                }  | 
            
| 30 | 30 | 
                 | 
            
| 31 | 
                +public var ShareRecentGroupInfo = RecentGroupInfo()  | 
            |
| 32 | 
                +  | 
            |
| 31 | 33 | 
                 public struct RecentGroupInfo {
               | 
            
| 32 | 34 | 
                 | 
            
| 33 | 
                -    public static var share: RecentGroupInfo {
               | 
            |
| 34 | 
                - return RecentGroupInfo()  | 
            |
| 35 | 
                - }  | 
            |
| 36 | 
                -  | 
            |
| 37 | 35 | 
                private var infos: [GroupItem]  | 
            
| 38 | 36 | 
                private var lock: NSLock  | 
            
| 39 | 37 | 
                     public var count: Int {
               | 
            
                @@ -51,9 +49,12 @@ public struct RecentGroupInfo {
               | 
            ||
| 51 | 49 | 
                 | 
            
| 52 | 50 | 
                     mutating public func add(_ item: GroupItem) {
               | 
            
| 53 | 51 | 
                lock.lock()  | 
            
| 52 | 
                +        infos.removeAll(where: { $0.group_id == item.group_id })
               | 
            |
| 53 | 
                +  | 
            |
| 54 | 54 | 
                         if infos.count == 3 {
               | 
            
| 55 | 55 | 
                infos.removeFirst()  | 
            
| 56 | 56 | 
                }  | 
            
| 57 | 
                +  | 
            |
| 57 | 58 | 
                infos.append(item)  | 
            
| 58 | 59 | 
                lock.unlock()  | 
            
| 59 | 60 | 
                }  | 
            
                @@ -23,40 +23,40 @@ struct GroupDetailRemoteAPI {
               | 
            ||
| 23 | 23 | 
                 | 
            
| 24 | 24 | 
                     func loadContent() -> Single<GroupDetailItem> {
               | 
            
| 25 | 25 | 
                let resource = ContentResource<GroupDetailItem>(path: .groupDetail,  | 
            
| 26 | 
                - parameter: ["user_id": "", "group_id": groupId],  | 
            |
| 26 | 
                + parameter: ["user_id": ShareUserId, "group_id": groupId],  | 
            |
| 27 | 27 | 
                parseJSON: parse)  | 
            
| 28 | 28 | 
                return resource.loadContent()  | 
            
| 29 | 29 | 
                }  | 
            
| 30 | 30 | 
                 | 
            
| 31 | 31 | 
                     func quit() -> Completable {
               | 
            
| 32 | 32 | 
                let quitResoure = StatusResource(path: .groupQuit,  | 
            
| 33 | 
                - parameter: ["user_id": "", "group_id": groupId])  | 
            |
| 33 | 
                + parameter: ["user_id": ShareUserId, "group_id": groupId])  | 
            |
| 34 | 34 | 
                return quitResoure.getStatus()  | 
            
| 35 | 35 | 
                }  | 
            
| 36 | 36 | 
                 | 
            
| 37 | 37 | 
                     func lock() -> Completable {
               | 
            
| 38 | 38 | 
                let lockResource = StatusResource(path: .groupLock,  | 
            
| 39 | 
                - parameter: ["user_id": "", "group_id": groupId])  | 
            |
| 39 | 
                + parameter: ["user_id": ShareUserId, "group_id": groupId])  | 
            |
| 40 | 40 | 
                return lockResource.getStatus()  | 
            
| 41 | 41 | 
                }  | 
            
| 42 | 42 | 
                 | 
            
| 43 | 43 | 
                     func unlock() -> Completable {
               | 
            
| 44 | 44 | 
                let unlockResource = StatusResource(path: .groupUnlock,  | 
            
| 45 | 
                - parameter: ["user_id": "", "group_id": groupId])  | 
            |
| 45 | 
                + parameter: ["user_id": ShareUserId, "group_id": groupId])  | 
            |
| 46 | 46 | 
                return unlockResource.getStatus()  | 
            
| 47 | 47 | 
                }  | 
            
| 48 | 48 | 
                 | 
            
| 49 | 49 | 
                     func remove(userId: String) -> Completable {
               | 
            
| 50 | 
                - let deleteResource = StatusResource(path: .groupUnlock,  | 
            |
| 51 | 
                - parameter: ["admin_id": "",  | 
            |
| 50 | 
                + let deleteResource = StatusResource(path: .groupRemove,  | 
            |
| 51 | 
                + parameter: ["admin_id": ShareUserId,  | 
            |
| 52 | 52 | 
                "group_id": groupId,  | 
            
| 53 | 
                - "user_id": ""])  | 
            |
| 53 | 
                + "user_id": userId])  | 
            |
| 54 | 54 | 
                return deleteResource.getStatus()  | 
            
| 55 | 55 | 
                }  | 
            
| 56 | 56 | 
                 | 
            
| 57 | 57 | 
                     func update(name: String) -> Completable {
               | 
            
| 58 | 58 | 
                let updateResource = StatusResource(path: .groupUpdate,  | 
            
| 59 | 
                - parameter: ["admin_id": "",  | 
            |
| 59 | 
                + parameter: ["admin_id": ShareUserId,  | 
            |
| 60 | 60 | 
                "group_id": groupId,  | 
            
| 61 | 61 | 
                "group_name": name])  | 
            
| 62 | 62 | 
                return updateResource.getStatus()  | 
            
                @@ -39,7 +39,8 @@ struct GroupRemoteAPI {
               | 
            ||
| 39 | 39 | 
                 | 
            
| 40 | 40 | 
                     func create(groupName: String, avatar: String) -> Single<GroupItem> {
               | 
            
| 41 | 41 | 
                let createResource = ContentResource<GroupItem>(path: .groupCreate,  | 
            
| 42 | 
                - parameter: ["group_name": groupName,  | 
            |
| 42 | 
                + parameter: ["user_id": ShareUserId,  | 
            |
| 43 | 
                + "group_name": groupName,  | 
            |
| 43 | 44 | 
                "group_default_avatar": avatar],  | 
            
| 44 | 45 | 
                parseJSON: parseGroup)  | 
            
| 45 | 46 | 
                return createResource.loadContent()  | 
            
                @@ -1,5 +1,5 @@  | 
            ||
| 1 | 1 | 
                //  | 
            
| 2 | 
                -// HomePhotoRemoteAPI.swift  | 
            |
| 2 | 
                +// HomeRemoteAPI.swift  | 
            |
| 3 | 3 | 
                // PaiaiDataKit  | 
            
| 4 | 4 | 
                //  | 
            
| 5 | 5 | 
                // Created by ffib on 2018/12/27.  | 
            
                @@ -9,7 +9,7 @@  | 
            ||
| 9 | 9 | 
                import Foundation  | 
            
| 10 | 10 | 
                import RxSwift  | 
            
| 11 | 11 | 
                 | 
            
| 12 | 
                -struct HomePhotoRemoteAPI {
               | 
            |
| 12 | 
                +struct HomeRemoteAPI {
               | 
            |
| 13 | 13 | 
                 | 
            
| 14 | 14 | 
                     private func parse(_ json: JSON) -> NetworkArrayData<PhotoItem>? {
               | 
            
| 15 | 15 | 
                         guard let data  = json["data"] as? [String: AnyObject] else { return nil }
               | 
            
                @@ -17,10 +17,40 @@ struct MessageRemoteAPI {
               | 
            ||
| 17 | 17 | 
                         return  messages.map { MessageItem(json: $0) }
               | 
            
| 18 | 18 | 
                }  | 
            
| 19 | 19 | 
                 | 
            
| 20 | 
                +    private func parseMessageList(_ json: JSON) -> NetworkArrayData<MessageListItem>? {
               | 
            |
| 21 | 
                +        guard let data  = json["data"] as? [String: AnyObject] else { return nil }
               | 
            |
| 22 | 
                + return NetworkArrayData<MessageListItem>(json: data, dataField: "messages")  | 
            |
| 23 | 
                + }  | 
            |
| 24 | 
                +  | 
            |
| 20 | 25 | 
                     func loadContent() -> Single<[MessageItem]> {
               | 
            
| 21 | 26 | 
                let resource = ContentResource<[MessageItem]>(path: .mesList,  | 
            
| 22 | 27 | 
                parameter: ["user_id": ShareUserId],  | 
            
| 23 | 28 | 
                parseJSON: parse)  | 
            
| 24 | 29 | 
                return resource.loadContent()  | 
            
| 25 | 30 | 
                }  | 
            
| 31 | 
                +  | 
            |
| 32 | 
                +    func loadMessageList(_ type: MessageType, page: Int) -> Single<NetworkArrayData<MessageListItem>> {
               | 
            |
| 33 | 
                + let resource = ContentResource<NetworkArrayData<MessageListItem>>(path: type.model.path,  | 
            |
| 34 | 
                + parameter: ["user_id": ShareUserId, "page": page],  | 
            |
| 35 | 
                + parseJSON: parseMessageList)  | 
            |
| 36 | 
                + return resource.loadContent()  | 
            |
| 37 | 
                + }  | 
            |
| 38 | 
                +  | 
            |
| 39 | 
                +    func remove(_ type: MessageType, pk: Int) -> Completable {
               | 
            |
| 40 | 
                + let removeResource = StatusResource(path: type.model.removePath,  | 
            |
| 41 | 
                + parameter: ["user_id": ShareUserId, "pk": pk])  | 
            |
| 42 | 
                + return removeResource.getStatus()  | 
            |
| 43 | 
                + }  | 
            |
| 44 | 
                +  | 
            |
| 45 | 
                +    func removeAll(_ type: MessageType) -> Completable {
               | 
            |
| 46 | 
                + let removeResource = StatusResource(path: type.model.removePath,  | 
            |
| 47 | 
                + parameter: ["user_id": ShareUserId, "all": true])  | 
            |
| 48 | 
                + return removeResource.getStatus()  | 
            |
| 49 | 
                + }  | 
            |
| 50 | 
                +  | 
            |
| 51 | 
                +    func readed(_ type: MessageType) -> Completable {
               | 
            |
| 52 | 
                + let readedResource = StatusResource(path: type.model.readPath,  | 
            |
| 53 | 
                + parameter: ["user_id": ShareUserId])  | 
            |
| 54 | 
                + return readedResource.getStatus()  | 
            |
| 55 | 
                + }  | 
            |
| 26 | 56 | 
                }  | 
            
                @@ -7,3 +7,74 @@  | 
            ||
| 7 | 7 | 
                //  | 
            
| 8 | 8 | 
                 | 
            
| 9 | 9 | 
                import Foundation  | 
            
| 10 | 
                +import RxSwift  | 
            |
| 11 | 
                +  | 
            |
| 12 | 
                +struct PhotoDetailRemoteAPI {
               | 
            |
| 13 | 
                + var photoId: String  | 
            |
| 14 | 
                + var groupId: String  | 
            |
| 15 | 
                +    init(photoId: String, groupId: String) {
               | 
            |
| 16 | 
                + self.photoId = photoId  | 
            |
| 17 | 
                + self.groupId = groupId  | 
            |
| 18 | 
                + }  | 
            |
| 19 | 
                +  | 
            |
| 20 | 
                +    private func parseCommtents(_ json: JSON) -> [PhotoCommentItem] {
               | 
            |
| 21 | 
                + guard let data = json["data"] as? [String: AnyObject],  | 
            |
| 22 | 
                +            let comments = data["comments"] as? [[String: AnyObject]] else { return [] }
               | 
            |
| 23 | 
                +        return comments.compactMap { PhotoCommentItem(json: $0) }
               | 
            |
| 24 | 
                + }  | 
            |
| 25 | 
                +  | 
            |
| 26 | 
                +    private func parseThumbups(_ json: JSON) -> [PhotoThumbupUserItem] {
               | 
            |
| 27 | 
                + guard let data = json["data"] as? [String: AnyObject],  | 
            |
| 28 | 
                +            let thumbups = data["thumbups"] as? [[String: AnyObject]] else { return [] }
               | 
            |
| 29 | 
                +        return thumbups.compactMap { PhotoThumbupUserItem(json: $0) }
               | 
            |
| 30 | 
                + }  | 
            |
| 31 | 
                +  | 
            |
| 32 | 
                +    func loadThumbups() -> Single<[PhotoThumbupUserItem]> {
               | 
            |
| 33 | 
                + let resource = ContentResource<[PhotoThumbupUserItem]>(path: .thumbupList,  | 
            |
| 34 | 
                + parameter: ["group_id": groupId,  | 
            |
| 35 | 
                + "photo_id": photoId,  | 
            |
| 36 | 
                + "user_id": ShareUserId],  | 
            |
| 37 | 
                + parseJSON: parseThumbups)  | 
            |
| 38 | 
                +  | 
            |
| 39 | 
                + return resource.loadContent()  | 
            |
| 40 | 
                + }  | 
            |
| 41 | 
                +  | 
            |
| 42 | 
                +    func loadComments() -> Single<[PhotoCommentItem]> {
               | 
            |
| 43 | 
                + let resource = ContentResource<[PhotoCommentItem]>(path: .commentList,  | 
            |
| 44 | 
                + parameter: ["group_id": groupId,  | 
            |
| 45 | 
                + "photo_id": photoId,  | 
            |
| 46 | 
                + "user_id": ShareUserId],  | 
            |
| 47 | 
                + parseJSON: parseCommtents)  | 
            |
| 48 | 
                +  | 
            |
| 49 | 
                + return resource.loadContent()  | 
            |
| 50 | 
                + }  | 
            |
| 51 | 
                +  | 
            |
| 52 | 
                +    func submitComment(text: String) -> Single<[PhotoCommentItem]> {
               | 
            |
| 53 | 
                + let resource = ContentResource<[PhotoCommentItem]>(path: .commentSubmit,  | 
            |
| 54 | 
                + parameter: ["group_id": groupId,  | 
            |
| 55 | 
                + "photo_id": photoId,  | 
            |
| 56 | 
                + "user_id": ShareUserId,  | 
            |
| 57 | 
                + "comment": text],  | 
            |
| 58 | 
                + parseJSON: parseCommtents)  | 
            |
| 59 | 
                + return resource.loadContent()  | 
            |
| 60 | 
                +  | 
            |
| 61 | 
                + }  | 
            |
| 62 | 
                +  | 
            |
| 63 | 
                +    func submitThumbup() -> Single<[PhotoThumbupUserItem]> {
               | 
            |
| 64 | 
                + let resource = ContentResource<[PhotoThumbupUserItem]>(path: .thumbupSubmit,  | 
            |
| 65 | 
                + parameter: ["group_id": groupId,  | 
            |
| 66 | 
                + "photo_id": photoId,  | 
            |
| 67 | 
                + "user_id": ShareUserId],  | 
            |
| 68 | 
                + parseJSON: parseThumbups)  | 
            |
| 69 | 
                + return resource.loadContent()  | 
            |
| 70 | 
                + }  | 
            |
| 71 | 
                +  | 
            |
| 72 | 
                +    func cancelThumbup() {
               | 
            |
| 73 | 
                + let resource = ContentResource<[PhotoCommentItem]>(path: .thumbupCancel,  | 
            |
| 74 | 
                + parameter: ["group_id": groupId,  | 
            |
| 75 | 
                + "photo_id": photoId,  | 
            |
| 76 | 
                + "user_id": ShareUserId],  | 
            |
| 77 | 
                + parseJSON: parseCommtents)  | 
            |
| 78 | 
                + resource.loadContent()  | 
            |
| 79 | 
                + }  | 
            |
| 80 | 
                +}  | 
            
                @@ -46,7 +46,7 @@ public enum Interfaces: String {
               | 
            ||
| 46 | 46 | 
                case photoUpload = "/f/upload"  | 
            
| 47 | 47 | 
                case commentSubmit = "/f/comment/submit"  | 
            
| 48 | 48 | 
                case thumbupSubmit = "/f/thumbup/submit"  | 
            
| 49 | 
                - case thumbupCancle = "/f/thumbup/cancel"  | 
            |
| 49 | 
                + case thumbupCancel = "/f/thumbup/cancel"  | 
            |
| 50 | 50 | 
                case thumbupList = "/f/thumbup/list"  | 
            
| 51 | 51 | 
                case commentList = "/f/comment/list"  | 
            
| 52 | 52 | 
                case picPrice = "/f/price"  | 
            
                @@ -73,7 +73,6 @@ class NetworkApi {
               | 
            ||
| 73 | 73 | 
                }  | 
            
| 74 | 74 | 
                 | 
            
| 75 | 75 | 
                     public func post<A: Resource>(resource: A) -> Single<A.Model> {
               | 
            
| 76 | 
                - print(resource)  | 
            |
| 77 | 76 | 
                         return Single<A.Model>.create(subscribe: { observer in
               | 
            
| 78 | 77 | 
                let request = self.session.request(resource.host + resource.path.rawValue,  | 
            
| 79 | 78 | 
                method: .post,  | 
            
                @@ -82,11 +81,17 @@ class NetworkApi {
               | 
            ||
| 82 | 81 | 
                                     switch res.result {
               | 
            
| 83 | 82 | 
                case .success(let json):  | 
            
| 84 | 83 | 
                guard let json = json as? [String: AnyObject],  | 
            
| 84 | 
                + let status = json["status"] as? Int,  | 
            |
| 85 | 85 | 
                                             let data = resource.parse(json) else {
               | 
            
| 86 | 86 | 
                observer(.error(ParseError()))  | 
            
| 87 | 87 | 
                return  | 
            
| 88 | 88 | 
                }  | 
            
| 89 | 
                - observer(.success(data))  | 
            |
| 89 | 
                +                        if status == 200 {
               | 
            |
| 90 | 
                + observer(.success(data))  | 
            |
| 91 | 
                +                        } else {
               | 
            |
| 92 | 
                + observer(.error(InteractionError(id: status, errMessage: "")))  | 
            |
| 93 | 
                + }  | 
            |
| 94 | 
                +  | 
            |
| 90 | 95 | 
                case .failure(let error):  | 
            
| 91 | 96 | 
                observer(.error(error))  | 
            
| 92 | 97 | 
                }  | 
            
                @@ -118,7 +123,6 @@ class NetworkApi {
               | 
            ||
| 118 | 123 | 
                }  | 
            
| 119 | 124 | 
                 | 
            
| 120 | 125 | 
                     public func upload<A: Resource>(resource: A) -> Single<A.Model> {
               | 
            
| 121 | 
                - print(resource.parameter)  | 
            |
| 122 | 126 | 
                         return Single<A.Model>.create(subscribe: { (observer) in
               | 
            
| 123 | 127 | 
                             let request = self.session.upload(multipartFormData: { (multiPartData) in
               | 
            
| 124 | 128 | 
                                 for (key, value) in resource.parameter {
               | 
            
                @@ -9,8 +9,6 @@  | 
            ||
| 9 | 9 | 
                import Foundation  | 
            
| 10 | 10 | 
                import RxSwift  | 
            
| 11 | 11 | 
                 | 
            
| 12 | 
                -  | 
            |
| 13 | 
                -  | 
            |
| 14 | 12 | 
                 struct StatusResource: Resource {
               | 
            
| 15 | 13 | 
                typealias Model = StatusModel  | 
            
| 16 | 14 | 
                 | 
            
                @@ -1,28 +0,0 @@  | 
            ||
| 1 | 
                -//  | 
            |
| 2 | 
                -// UserSessionRepository.swift  | 
            |
| 3 | 
                -// PaiAi  | 
            |
| 4 | 
                -//  | 
            |
| 5 | 
                -// Created by FFIB on 16/4/1.  | 
            |
| 6 | 
                -// Copyright © 2016年 FFIB. All rights reserved.  | 
            |
| 7 | 
                -//  | 
            |
| 8 | 
                -  | 
            |
| 9 | 
                -import Foundation  | 
            |
| 10 | 
                -  | 
            |
| 11 | 
                -final class UserInfoRepository {
               | 
            |
| 12 | 
                -  | 
            |
| 13 | 
                - fileprivate var loginRemoteAPI: LoginRemoteAPI  | 
            |
| 14 | 
                - fileprivate var userSessionStore: UserSessionStore  | 
            |
| 15 | 
                - init(loginRemoteAPI: LoginRemoteAPI = LoginRemoteAPI(),  | 
            |
| 16 | 
                -         userSessionStore: UserSessionStore = UserSessionStore()) {
               | 
            |
| 17 | 
                - self.loginRemoteAPI = loginRemoteAPI  | 
            |
| 18 | 
                - self.userSessionStore = userSessionStore  | 
            |
| 19 | 
                - }  | 
            |
| 20 | 
                -  | 
            |
| 21 | 
                -    func guestLogin() {
               | 
            |
| 22 | 
                - loginRemoteAPI.guestLogin()  | 
            |
| 23 | 
                - }  | 
            |
| 24 | 
                -  | 
            |
| 25 | 
                -    func wxLogin() {
               | 
            |
| 26 | 
                - loginRemoteAPI.wxLogin()  | 
            |
| 27 | 
                - }  | 
            |
| 28 | 
                -}  | 
            
                @@ -10,83 +10,98 @@ import Foundation  | 
            ||
| 10 | 10 | 
                import RxSwift  | 
            
| 11 | 11 | 
                import RxCocoa  | 
            
| 12 | 12 | 
                 | 
            
| 13 | 
                -protocol GroupDetailViewModelDelegate {
               | 
            |
| 14 | 
                -  | 
            |
| 13 | 
                +public protocol GroupDetailViewModelDelegate: class {
               | 
            |
| 14 | 
                + func navigationToGroupMember(_ item: GroupDetailItem)  | 
            |
| 15 | 
                + func navigationToGroupNameModification(_ item: GroupDetailItem)  | 
            |
| 16 | 
                + func navigationToRootViewController()  | 
            |
| 15 | 17 | 
                }  | 
            
| 16 | 18 | 
                 | 
            
| 17 | 19 | 
                 public class GroupDetailViewModel {
               | 
            
| 18 | 20 | 
                 | 
            
| 19 | 
                - private let respository: GroupDetailRepository  | 
            |
| 20 | 
                - private let item: BehaviorRelay<GroupDetailItem>  | 
            |
| 21 | 
                + private let repository: GroupDetailRepository  | 
            |
| 22 | 
                + private var disposeBag = DisposeBag()  | 
            |
| 23 | 
                +  | 
            |
| 24 | 
                + public weak var delegate: GroupDetailViewModelDelegate?  | 
            |
| 25 | 
                +  | 
            |
| 26 | 
                + public let item: BehaviorRelay<GroupDetailItem>  | 
            |
| 27 | 
                +    public var groupName: Observable<String> {
               | 
            |
| 28 | 
                +        return item.asObservable().flatMapLatest({ (item) -> Observable<String> in
               | 
            |
| 29 | 
                + return Observable.just(item.group.group_name)  | 
            |
| 30 | 
                + })  | 
            |
| 31 | 
                + }  | 
            |
| 32 | 
                +  | 
            |
| 33 | 
                +    public var groupMembers: Observable<[GroupMemberItem]> {
               | 
            |
| 34 | 
                +        return item.asObservable().flatMapLatest({ (item) -> Observable<[GroupMemberItem]> in
               | 
            |
| 35 | 
                + return Observable.just(item.users)  | 
            |
| 36 | 
                + })  | 
            |
| 37 | 
                + }  | 
            |
| 38 | 
                +  | 
            |
| 39 | 
                +    public var groupMemberCount: Observable<String> {
               | 
            |
| 40 | 
                +        return item.asObservable().flatMapLatest({ (item) -> Observable<String> in
               | 
            |
| 41 | 
                +            return Observable.just("\(item.users.count)")
               | 
            |
| 42 | 
                + })  | 
            |
| 43 | 
                + }  | 
            |
| 44 | 
                +  | 
            |
| 45 | 
                +    public var isAdmin: Observable<Bool> {
               | 
            |
| 46 | 
                +        return item.asObservable().flatMapLatest({ (item) -> Observable<Bool> in
               | 
            |
| 47 | 
                + return Observable.just(item.group.admin_id == ShareUserId)  | 
            |
| 48 | 
                + })  | 
            |
| 49 | 
                + }  | 
            |
| 21 | 50 | 
                 | 
            
| 22 | 
                -    public init(groupId: String) {
               | 
            |
| 23 | 
                - self.respository = PhotoGroupDetailRepository(groupId: groupId)  | 
            |
| 24 | 
                - item = BehaviorRelay<GroupDetailItem>(value: GroupDetailItem(json: [:]))  | 
            |
| 51 | 
                +    public var groupLock: Observable<Bool> {
               | 
            |
| 52 | 
                +        return item.asObservable().flatMapLatest({ (item) -> Observable<Bool> in
               | 
            |
| 53 | 
                + return Observable.just(item.group.group_lock)  | 
            |
| 54 | 
                + })  | 
            |
| 25 | 55 | 
                }  | 
            
| 26 | 56 | 
                 | 
            
| 27 | 
                -    public var contents: Observable<GroupDetailItem> {
               | 
            |
| 28 | 
                - return item.asObservable()  | 
            |
| 57 | 
                +    public init(item: GroupItem) {
               | 
            |
| 58 | 
                + self.repository = PhotoGroupDetailRepository(groupId: item.group_id)  | 
            |
| 59 | 
                +  | 
            |
| 60 | 
                + var groupDetailItem = GroupDetailItem(json: [:])  | 
            |
| 61 | 
                + groupDetailItem.group = item  | 
            |
| 62 | 
                + self.item = BehaviorRelay<GroupDetailItem>(value: groupDetailItem)  | 
            |
| 29 | 63 | 
                }  | 
            
| 30 | 64 | 
                 | 
            
| 31 | 65 | 
                     public func toggle(isLock: Bool) {
               | 
            
| 32 | 
                -// return respository.update(data: isLock)  | 
            |
| 66 | 
                +        if isLock {
               | 
            |
| 67 | 
                +            repository.lock().subscribe(onCompleted: {
               | 
            |
| 68 | 
                + var v = self.item.value  | 
            |
| 69 | 
                + v.group.group_lock = true  | 
            |
| 70 | 
                + self.item.accept(v)  | 
            |
| 71 | 
                +            }) { (error) in
               | 
            |
| 72 | 
                +  | 
            |
| 73 | 
                + }.disposed(by: disposeBag)  | 
            |
| 74 | 
                +        } else {
               | 
            |
| 75 | 
                +            repository.unlock().subscribe(onCompleted: {
               | 
            |
| 76 | 
                + var v = self.item.value  | 
            |
| 77 | 
                + v.group.group_lock = false  | 
            |
| 78 | 
                + }, onError: nil).disposed(by: disposeBag)  | 
            |
| 79 | 
                + }  | 
            |
| 33 | 80 | 
                }  | 
            
| 34 | 81 | 
                 | 
            
| 35 | 82 | 
                     public func reload() {
               | 
            
| 36 | 
                - respository.load()  | 
            |
| 83 | 
                +        repository.load().subscribe(onSuccess: {[unowned self] (v) in
               | 
            |
| 84 | 
                + self.item.accept(v)  | 
            |
| 85 | 
                + }, onError: nil).disposed(by: disposeBag)  | 
            |
| 37 | 86 | 
                }  | 
            
| 38 | 87 | 
                 | 
            
| 39 | 88 | 
                     public func quit() {
               | 
            
| 40 | 
                - respository.quit()  | 
            |
| 89 | 
                +        guard item.value.group.admin_id != ShareUserId else {
               | 
            |
| 90 | 
                + return  | 
            |
| 91 | 
                + }  | 
            |
| 92 | 
                + repository.quit()  | 
            |
| 93 | 
                +            .subscribe(onCompleted: {[unowned self] in
               | 
            |
| 94 | 
                + self.delegate?.navigationToRootViewController()  | 
            |
| 95 | 
                + }).disposed(by: disposeBag)  | 
            |
| 41 | 96 | 
                }  | 
            
| 42 | 97 | 
                }  | 
            
| 43 | 98 | 
                 | 
            
| 44 | 
                -//public struct GroupDetailViewModel {
               | 
            |
| 45 | 
                -// public var groupDetailData = Variable<GroupDetailModel>(GroupDetailModel())  | 
            |
| 46 | 
                -//  | 
            |
| 47 | 
                -//    public init() {
               | 
            |
| 48 | 
                -//  | 
            |
| 49 | 
                -// }  | 
            |
| 50 | 
                -//  | 
            |
| 51 | 
                -//    public func fetchGroupDetailData(groupId: String) {
               | 
            |
| 52 | 
                -// let params = ["group_id": groupId,  | 
            |
| 53 | 
                -// "user_id": SharedUserInfo.userId] as [String: AnyObject]  | 
            |
| 54 | 
                -// let request = GroupDetailNetworkQequest(param: params, path: .groupDetail)  | 
            |
| 55 | 
                -//        networkApi.post(request: request) { (res) in
               | 
            |
| 56 | 
                -// self.groupDetailData.value = res  | 
            |
| 57 | 
                -//// FFToastView.hideLoadingToast()  | 
            |
| 58 | 
                -// }  | 
            |
| 59 | 
                -// }  | 
            |
| 60 | 
                -//  | 
            |
| 61 | 
                -//    public func quitQroup(success: @escaping () -> Void) {
               | 
            |
| 62 | 
                -////        if groupDetailData.value.group?.admin_id == SharedUserInfo.userId {
               | 
            |
| 63 | 
                -//// FFToastView.showToast(inView: UIApplication.shared.keyWindow!, withText: "管理员不能退出")  | 
            |
| 64 | 
                -//// return  | 
            |
| 65 | 
                -////        } else {
               | 
            |
| 66 | 
                -// let params = ["group_id": groupDetailData.value.group_id,  | 
            |
| 67 | 
                -// "user_id": SharedUserInfo.userId] as [String: AnyObject]  | 
            |
| 68 | 
                -// let request = StatusNetworkRequest(param: params, path: .groupQuit)  | 
            |
| 69 | 
                -//            networkApi.post(request: request, handler: { (res) in
               | 
            |
| 70 | 
                -//                guard res.status == 200 else {
               | 
            |
| 71 | 
                -// return  | 
            |
| 72 | 
                -// }  | 
            |
| 73 | 
                -// success()  | 
            |
| 74 | 
                -// PhotoLocalStorage.instance.removeLocalData(group_id: self.groupDetailData.value.group_id)  | 
            |
| 75 | 
                -// })  | 
            |
| 76 | 
                -//// }  | 
            |
| 77 | 
                -// }  | 
            |
| 78 | 
                -//  | 
            |
| 79 | 
                -//    public func postLock(isLock: Bool) {
               | 
            |
| 80 | 
                -// let url = isLock ? Interfaces.groupLock : Interfaces.groupUnlock  | 
            |
| 81 | 
                -//// self.groupDetailData.value.group?.group_lock = isLock  | 
            |
| 82 | 
                -// let params = ["group_id": groupDetailData.value.group_id,  | 
            |
| 83 | 
                -// "user_id": SharedUserInfo.userId] as [String: AnyObject]  | 
            |
| 84 | 
                -// let request = StatusNetworkRequest(param: params, path: url)  | 
            |
| 85 | 
                -//        networkApi.post(request: request) { (res) in
               | 
            |
| 86 | 
                -//            guard res.status == 200 else {
               | 
            |
| 87 | 
                -// return  | 
            |
| 88 | 
                -// }  | 
            |
| 89 | 
                -//// FFToastView.showToast(inView: UIApplication.shared.keyWindow!, withText: res.message)  | 
            |
| 90 | 
                -// }  | 
            |
| 91 | 
                -// }  | 
            |
| 92 | 
                -//}  | 
            |
| 99 | 
                +public extension GroupDetailViewModel {
               | 
            |
| 100 | 
                +    func navigationToGroupMember() {
               | 
            |
| 101 | 
                + delegate?.navigationToGroupMember(item.value)  | 
            |
| 102 | 
                + }  | 
            |
| 103 | 
                +  | 
            |
| 104 | 
                +    func navigationToGroupNameModification() {
               | 
            |
| 105 | 
                + delegate?.navigationToGroupNameModification(item.value)  | 
            |
| 106 | 
                + }  | 
            |
| 107 | 
                +}  | 
            
                @@ -7,14 +7,37 @@  | 
            ||
| 7 | 7 | 
                //  | 
            
| 8 | 8 | 
                 | 
            
| 9 | 9 | 
                import UIKit  | 
            
| 10 | 
                +import RxSwift  | 
            |
| 11 | 
                +import RxCocoa  | 
            |
| 12 | 
                +import RxDataSources  | 
            |
| 10 | 13 | 
                 | 
            
| 11 | 14 | 
                 public class GroupMemberViewModel {
               | 
            
| 12 | 15 | 
                 | 
            
| 13 | 
                - public var isManage: Bool = false  | 
            |
| 14 | 
                -    public init() {}
               | 
            |
| 15 | 
                -    public func deleteUser(_ index: Int) {
               | 
            |
| 16 | 
                -//        NetworkApi.share.post(resource: self) { (result) in
               | 
            |
| 17 | 
                -//            guard case let .success(data) = result else { return }
               | 
            |
| 18 | 
                -// }  | 
            |
| 16 | 
                + private var repository: PhotoGroupDetailRepository  | 
            |
| 17 | 
                + private var items: BehaviorRelay<[GroupMemberItem]>  | 
            |
| 18 | 
                +  | 
            |
| 19 | 
                + private var disposeBag = DisposeBag()  | 
            |
| 20 | 
                +  | 
            |
| 21 | 
                + public var isAdmin: Bool  | 
            |
| 22 | 
                +  | 
            |
| 23 | 
                +    public var contents: Observable<[AnimatableSectionModel<Int, GroupMemberItem>]> {
               | 
            |
| 24 | 
                +        return items.map({ model in
               | 
            |
| 25 | 
                + return [AnimatableSectionModel(model: 0, items: model)]  | 
            |
| 26 | 
                + })  | 
            |
| 27 | 
                + }  | 
            |
| 28 | 
                +  | 
            |
| 29 | 
                +    public init(item: GroupDetailItem) {
               | 
            |
| 30 | 
                + self.repository = PhotoGroupDetailRepository(groupId: item.group_id)  | 
            |
| 31 | 
                + self.items = BehaviorRelay<[GroupMemberItem]>(value: item.users)  | 
            |
| 32 | 
                + self.isAdmin = item.group.admin_id == ShareUserId  | 
            |
| 33 | 
                + }  | 
            |
| 34 | 
                +  | 
            |
| 35 | 
                +    public func removeMember(_ item: GroupMemberItem) {
               | 
            |
| 36 | 
                + repository.removeMember(userId: item.user_id)  | 
            |
| 37 | 
                +            .subscribe(onCompleted: {[unowned self] in
               | 
            |
| 38 | 
                + var content = self.items.value  | 
            |
| 39 | 
                +                content.removeAll(where: { $0.user_id == item.user_id })
               | 
            |
| 40 | 
                + self.items.accept(content)  | 
            |
| 41 | 
                + }).disposed(by: disposeBag)  | 
            |
| 19 | 42 | 
                }  | 
            
| 20 | 43 | 
                }  | 
            
                @@ -12,19 +12,33 @@ import RxCocoa  | 
            ||
| 12 | 12 | 
                import RxDataSources  | 
            
| 13 | 13 | 
                 | 
            
| 14 | 14 | 
                 public protocol GroupViewModelDelegate: class {
               | 
            
| 15 | 
                - func didSelect(_ item: PhotoItem)  | 
            |
| 16 | 
                - func navigateToGroupDetail()  | 
            |
| 15 | 
                + func didSelect(_ items: [PhotoItem], currIndex: Int)  | 
            |
| 16 | 
                + func navigateToGroupDetail(_ item: GroupItem)  | 
            |
| 17 | 17 | 
                }  | 
            
| 18 | 18 | 
                 | 
            
| 19 | 19 | 
                 public class GroupViewModel {
               | 
            
| 20 | 20 | 
                 | 
            
| 21 | 21 | 
                private let disposeBag = DisposeBag()  | 
            
| 22 | 22 | 
                 | 
            
| 23 | 
                - private var respository: GroupPhotoRepository  | 
            |
| 23 | 
                + private var repository: GroupPhotoRepository  | 
            |
| 24 | 
                +  | 
            |
| 24 | 25 | 
                 | 
            
| 25 | 26 | 
                private var _isLoading = PublishSubject<Void>()  | 
            
| 26 | 27 | 
                private let items = BehaviorRelay<[PhotoItem]>(value: [])  | 
            
| 27 | 28 | 
                 | 
            
| 29 | 
                + public var groupItem: BehaviorRelay<GroupItem>  | 
            |
| 30 | 
                +  | 
            |
| 31 | 
                +    public var groupName: Observable<String> {
               | 
            |
| 32 | 
                +        return groupItem.asObservable().flatMapLatest({ (item) -> Observable<String> in
               | 
            |
| 33 | 
                + return Observable.just(item.group_name)  | 
            |
| 34 | 
                + })  | 
            |
| 35 | 
                + }  | 
            |
| 36 | 
                +  | 
            |
| 37 | 
                +    public var groupAvatar: Observable<String> {
               | 
            |
| 38 | 
                +        return groupItem.asObservable().flatMapLatest({ (item) -> Observable<String> in
               | 
            |
| 39 | 
                +            return Observable.just("Group\(item.group_default_avatar)")
               | 
            |
| 40 | 
                + })  | 
            |
| 41 | 
                + }  | 
            |
| 28 | 42 | 
                 | 
            
| 29 | 43 | 
                     public var isLoading: Observable<Void> {
               | 
            
| 30 | 44 | 
                return _isLoading.asObservable()  | 
            
                @@ -39,11 +53,13 @@ public class GroupViewModel {
               | 
            ||
| 39 | 53 | 
                public weak var delegate: GroupViewModelDelegate?  | 
            
| 40 | 54 | 
                 | 
            
| 41 | 55 | 
                     public init(groupItem: GroupItem) {
               | 
            
| 42 | 
                - self.respository = GroupPhotoRepository(groupId: groupItem.group_id)  | 
            |
| 56 | 
                + self.repository = GroupPhotoRepository(groupId: groupItem.group_id)  | 
            |
| 57 | 
                + self.groupItem = BehaviorRelay<GroupItem>(value: groupItem)  | 
            |
| 58 | 
                + ShareRecentGroupInfo.add(groupItem)  | 
            |
| 43 | 59 | 
                }  | 
            
| 44 | 60 | 
                 | 
            
| 45 | 61 | 
                     public func reload() {
               | 
            
| 46 | 
                - respository.load()  | 
            |
| 62 | 
                + repository.load()  | 
            |
| 47 | 63 | 
                             .subscribe(onSuccess: {[weak self] (result) in
               | 
            
| 48 | 64 | 
                                 guard let `self` = self else { return }
               | 
            
| 49 | 65 | 
                self._isLoading.onNext(())  | 
            
                @@ -55,7 +71,7 @@ public class GroupViewModel {
               | 
            ||
| 55 | 71 | 
                }  | 
            
| 56 | 72 | 
                 | 
            
| 57 | 73 | 
                     public func submit(data: Data) {
               | 
            
| 58 | 
                -        respository.upload(data: data).subscribe(onSuccess: { [weak self] result in
               | 
            |
| 74 | 
                +        repository.upload(data: data).subscribe(onSuccess: { [weak self] result in
               | 
            |
| 59 | 75 | 
                             guard let `self` = self else { return }
               | 
            
| 60 | 76 | 
                self.items.accept(result)  | 
            
| 61 | 77 | 
                self._isLoading.onNext(())  | 
            
                @@ -77,11 +93,11 @@ public class GroupViewModel {
               | 
            ||
| 77 | 93 | 
                 | 
            
| 78 | 94 | 
                /// GroupViewModelDelegate  | 
            
| 79 | 95 | 
                 public extension GroupViewModel {
               | 
            
| 80 | 
                -    func didSelect(_ item: PhotoItem) {
               | 
            |
| 81 | 
                - delegate?.didSelect(item)  | 
            |
| 96 | 
                +    func didSelect(_ index: Int) {
               | 
            |
| 97 | 
                + delegate?.didSelect(items.value, currIndex: index)  | 
            |
| 82 | 98 | 
                }  | 
            
| 83 | 99 | 
                 | 
            
| 84 | 100 | 
                     @objc func navigateToGroupDetail() {
               | 
            
| 85 | 
                - delegate?.navigateToGroupDetail()  | 
            |
| 101 | 
                + delegate?.navigateToGroupDetail(groupItem.value)  | 
            |
| 86 | 102 | 
                }  | 
            
| 87 | 103 | 
                }  | 
            
                @@ -1,5 +1,5 @@  | 
            ||
| 1 | 1 | 
                //  | 
            
| 2 | 
                -// CreateGroupConfirmViewModel.swift  | 
            |
| 2 | 
                +// CreateGroupViewModel.swift  | 
            |
| 3 | 3 | 
                // PaiAi  | 
            
| 4 | 4 | 
                //  | 
            
| 5 | 5 | 
                // Created by ffib on 2018/12/17.  | 
            
                @@ -10,53 +10,39 @@ import Foundation  | 
            ||
| 10 | 10 | 
                import RxSwift  | 
            
| 11 | 11 | 
                import RxCocoa  | 
            
| 12 | 12 | 
                 | 
            
| 13 | 
                -fileprivate let DefaultGroupNames = ["苹果", "香蕉", "西兰花",  | 
            |
| 13 | 
                +public protocol CreateGroupViewModelDelegate: class {
               | 
            |
| 14 | 
                + func navigationToGroup(_ item: GroupItem)  | 
            |
| 15 | 
                +}  | 
            |
| 16 | 
                +  | 
            |
| 17 | 
                +public final class CreateGroupViewModel {
               | 
            |
| 18 | 
                +  | 
            |
| 19 | 
                + private var repository: PhotoGroupRepository  | 
            |
| 20 | 
                +  | 
            |
| 21 | 
                + public var avatar: String  | 
            |
| 22 | 
                + public var name: String  | 
            |
| 23 | 
                + public var mappingIndex: Int  | 
            |
| 24 | 
                + public weak var delegate: CreateGroupViewModelDelegate?  | 
            |
| 25 | 
                +  | 
            |
| 26 | 
                + private let defaultGroupNames = ["苹果", "香蕉", "西兰花",  | 
            |
| 14 | 27 | 
                "杨梅", "胡萝卜", "樱桃",  | 
            
| 15 | 28 | 
                "玉米", "火龙果", "茄子",  | 
            
| 16 | 29 | 
                "无花果", "葡萄", "柠檬",  | 
            
| 17 | 30 | 
                "山竹", "橘子", "木瓜",  | 
            
| 18 | 31 | 
                "水蜜桃", "菠萝", "草莓",  | 
            
| 19 | 32 | 
                "西瓜"]  | 
            
| 20 | 
                -  | 
            |
| 21 | 
                -public final class CreateGroupConfirmViewModel {
               | 
            |
| 22 | 
                -  | 
            |
| 23 | 
                - private var item: BehaviorRelay<GroupItem?>  | 
            |
| 24 | 
                - private var repository: PhotoGroupRepository  | 
            |
| 25 | 
                -  | 
            |
| 26 | 
                - public var avatar: Observable<String>  | 
            |
| 27 | 
                - public var name: Observable<String>  | 
            |
| 28 | 
                - public var groupModelUntilNotNil: Observable<GroupItem?>  | 
            |
| 29 | 
                -  | 
            |
| 33 | 
                + private let disposeBag = DisposeBag()  | 
            |
| 30 | 34 | 
                 | 
            
| 31 | 
                -    public init() {
               | 
            |
| 32 | 
                - repository = PhotoGroupRepository()  | 
            |
| 33 | 
                - let random = Int(arc4random_uniform(19))  | 
            |
| 34 | 
                -        avatar = Observable.create({ (observer) -> Disposable in
               | 
            |
| 35 | 
                - observer.onNext(DefaultGroupNames[random])  | 
            |
| 36 | 
                - return Disposables.create()  | 
            |
| 37 | 
                - })  | 
            |
| 38 | 
                -  | 
            |
| 39 | 
                -        name = avatar.flatMapLatest({ (currentAvatar) in
               | 
            |
| 40 | 
                -//            Observable.just("\(UserInfoViewModel)的\(currentAvatar)群")
               | 
            |
| 41 | 
                -            Observable.just("群")
               | 
            |
| 42 | 
                - }).share()  | 
            |
| 43 | 
                -  | 
            |
| 44 | 
                - item = BehaviorRelay<GroupItem?>(value: nil)  | 
            |
| 45 | 
                -  | 
            |
| 46 | 
                -        groupModelUntilNotNil = item.filter { $0 != nil }
               | 
            |
| 47 | 
                -  | 
            |
| 48 | 
                -        name.bind { (groupName) in
               | 
            |
| 49 | 
                -  | 
            |
| 50 | 
                -// self.parameter = ["group_name": groupName as AnyObject,  | 
            |
| 51 | 
                -// "group_default_avatar": random as AnyObject]  | 
            |
| 52 | 
                - }.dispose()  | 
            |
| 35 | 
                +    public init(userInfoViewModel: UserInfoViewModel) {
               | 
            |
| 36 | 
                + self.mappingIndex = Int(arc4random_uniform(19))  | 
            |
| 37 | 
                + self.repository = PhotoGroupRepository()  | 
            |
| 38 | 
                + self.avatar = "Group\(mappingIndex)"  | 
            |
| 39 | 
                + self.name = userInfoViewModel.shareUserInfo.value.userName + "的" + defaultGroupNames[mappingIndex] + "群"  | 
            |
| 53 | 40 | 
                }  | 
            
| 54 | 41 | 
                 | 
            
| 55 | 42 | 
                     public func createGroup() {
               | 
            
| 56 | 
                -// repository.create(groupName: avatar, avatar: <#T##String#>)  | 
            |
| 57 | 
                -//        NetworkApi.share.post(resource: self) { (result) in
               | 
            |
| 58 | 
                -//            guard case let .success(item) = result else { return }
               | 
            |
| 59 | 
                -// self.groupModel.accept(item)  | 
            |
| 60 | 
                -// }  | 
            |
| 43 | 
                + return repository.create(groupName: name, avatar: "\(mappingIndex)")  | 
            |
| 44 | 
                +            .subscribe(onSuccess: {[unowned self] item in
               | 
            |
| 45 | 
                + self.delegate?.navigationToGroup(item)  | 
            |
| 46 | 
                + }).disposed(by: disposeBag)  | 
            |
| 61 | 47 | 
                }  | 
            
| 62 | 48 | 
                }  | 
            
                @@ -14,7 +14,7 @@ import RxDataSources  | 
            ||
| 14 | 14 | 
                 public protocol HomeViewModelDelegate: class {
               | 
            
| 15 | 15 | 
                func scanQR()  | 
            
| 16 | 16 | 
                func createGroup()  | 
            
| 17 | 
                - func didSelect(_ item: PhotoItem)  | 
            |
| 17 | 
                + func didSelect(_ items: [PhotoItem], currIndex: Int)  | 
            |
| 18 | 18 | 
                }  | 
            
| 19 | 19 | 
                 | 
            
| 20 | 20 | 
                 public class HomeViewModel {
               | 
            
                @@ -22,7 +22,7 @@ public class HomeViewModel {
               | 
            ||
| 22 | 22 | 
                private var page: Int = 1  | 
            
| 23 | 23 | 
                private let disposeBag = DisposeBag()  | 
            
| 24 | 24 | 
                 | 
            
| 25 | 
                - private var respository: PhotoRepository  | 
            |
| 25 | 
                + private var repository: HomeRepository  | 
            |
| 26 | 26 | 
                 | 
            
| 27 | 27 | 
                private var _isLoading = PublishSubject<Bool>()  | 
            
| 28 | 28 | 
                private var _hasMoreData = BehaviorRelay<Bool>(value: true)  | 
            
                @@ -49,7 +49,7 @@ public class HomeViewModel {
               | 
            ||
| 49 | 49 | 
                public weak var delegate: HomeViewModelDelegate?  | 
            
| 50 | 50 | 
                 | 
            
| 51 | 51 | 
                     public init() {
               | 
            
| 52 | 
                - self.respository = HomePhotoRepository()  | 
            |
| 52 | 
                + self.repository = HomeRepository()  | 
            |
| 53 | 53 | 
                 | 
            
| 54 | 54 | 
                         scanBtnTapped.subscribe({
               | 
            
| 55 | 55 | 
                [weak self] (_) in  | 
            
                @@ -66,7 +66,7 @@ public class HomeViewModel {
               | 
            ||
| 66 | 66 | 
                 | 
            
| 67 | 67 | 
                     public func reload() {
               | 
            
| 68 | 68 | 
                page = 1  | 
            
| 69 | 
                - respository.load(page: page)  | 
            |
| 69 | 
                + repository.load(page: page)  | 
            |
| 70 | 70 | 
                             .subscribe(onSuccess: {[weak self] (result) in
               | 
            
| 71 | 71 | 
                                 guard let `self` = self else { return }
               | 
            
| 72 | 72 | 
                self._isLoading.onNext(true)  | 
            
                @@ -81,7 +81,7 @@ public class HomeViewModel {
               | 
            ||
| 81 | 81 | 
                     public func preload() {
               | 
            
| 82 | 82 | 
                         guard _hasMoreData.value else { return }
               | 
            
| 83 | 83 | 
                page += 1  | 
            
| 84 | 
                - respository.load(page: page)  | 
            |
| 84 | 
                + repository.load(page: page)  | 
            |
| 85 | 85 | 
                             .subscribe(onSuccess: {[weak self] (result) in
               | 
            
| 86 | 86 | 
                                 guard let `self` = self else { return }
               | 
            
| 87 | 87 | 
                self._isLoading.onNext(false)  | 
            
                @@ -114,7 +114,7 @@ extension HomeViewModel {
               | 
            ||
| 114 | 114 | 
                delegate?.createGroup()  | 
            
| 115 | 115 | 
                }  | 
            
| 116 | 116 | 
                 | 
            
| 117 | 
                -    public func didSelect(_ item: PhotoItem) {
               | 
            |
| 118 | 
                - delegate?.didSelect(item)  | 
            |
| 117 | 
                +    public func didSelect(_ currIndex: Int) {
               | 
            |
| 118 | 
                + delegate?.didSelect(items.value, currIndex: currIndex)  | 
            |
| 119 | 119 | 
                }  | 
            
| 120 | 120 | 
                }  | 
            
                @@ -16,10 +16,10 @@ public final class ScanQRViewModel {
               | 
            ||
| 16 | 16 | 
                 | 
            
| 17 | 17 | 
                weak var delegate: ScanQRViewModelDelegate?  | 
            
| 18 | 18 | 
                 | 
            
| 19 | 
                - var respository: PhotoGroupRepository  | 
            |
| 19 | 
                + var repository: PhotoGroupRepository  | 
            |
| 20 | 20 | 
                 | 
            
| 21 | 21 | 
                     public init() {
               | 
            
| 22 | 
                - respository = PhotoGroupRepository()  | 
            |
| 22 | 
                + repository = PhotoGroupRepository()  | 
            |
| 23 | 23 | 
                }  | 
            
| 24 | 24 | 
                 | 
            
| 25 | 25 | 
                     public func join(code: String) {
               | 
            
                @@ -31,10 +31,10 @@ public final class ScanQRViewModel {
               | 
            ||
| 31 | 31 | 
                guard let lensman_id = params.components(separatedBy: "=").last,  | 
            
| 32 | 32 | 
                                 let session_id = params.components(separatedBy: "?").first else { return }
               | 
            
| 33 | 33 | 
                 | 
            
| 34 | 
                - respository.join(type: .session, parameter: ["session_id": session_id, "lensman_id": lensman_id])  | 
            |
| 34 | 
                + repository.join(type: .session, parameter: ["session_id": session_id, "lensman_id": lensman_id])  | 
            |
| 35 | 35 | 
                 | 
            
| 36 | 36 | 
                case "g":  | 
            
| 37 | 
                - respository.join(type: .session, parameter: ["group_id": params])  | 
            |
| 37 | 
                + repository.join(type: .session, parameter: ["group_id": params])  | 
            |
| 38 | 38 | 
                default:  | 
            
| 39 | 39 | 
                return  | 
            
| 40 | 40 | 
                }  | 
            
                @@ -17,7 +17,8 @@ public protocol MessageListViewModelDelegate: class {
               | 
            ||
| 17 | 17 | 
                 | 
            
| 18 | 18 | 
                 public class MessageListViewModel {
               | 
            
| 19 | 19 | 
                 | 
            
| 20 | 
                - private let repository: MessageListRepository  | 
            |
| 20 | 
                + private let repository: MessageRepository  | 
            |
| 21 | 
                + private let type: MessageType  | 
            |
| 21 | 22 | 
                private var disposeBag = DisposeBag()  | 
            
| 22 | 23 | 
                private var page = 1  | 
            
| 23 | 24 | 
                 | 
            
                @@ -52,12 +53,13 @@ public class MessageListViewModel {
               | 
            ||
| 52 | 53 | 
                }  | 
            
| 53 | 54 | 
                 | 
            
| 54 | 55 | 
                     public init(type: MessageType) {
               | 
            
| 55 | 
                - self.repository = MessageListRepository(type: type)  | 
            |
| 56 | 
                + self.repository = MessageRepository()  | 
            |
| 57 | 
                + self.type = type  | 
            |
| 56 | 58 | 
                }  | 
            
| 57 | 59 | 
                 | 
            
| 58 | 60 | 
                     public func reload() {
               | 
            
| 59 | 61 | 
                page = 1  | 
            
| 60 | 
                - repository.load(page: page)  | 
            |
| 62 | 
                + repository.loadMessageList(type, page: page)  | 
            |
| 61 | 63 | 
                .asDriver(onErrorJustReturn: NetworkArrayData<MessageListItem>.empty())  | 
            
| 62 | 64 | 
                             .drive(onNext: {[weak self] (model) in
               | 
            
| 63 | 65 | 
                                 guard let `self` = self else { return }
               | 
            
                @@ -74,7 +76,7 @@ public class MessageListViewModel {
               | 
            ||
| 74 | 76 | 
                     public func preload() {
               | 
            
| 75 | 77 | 
                page += 1  | 
            
| 76 | 78 | 
                 | 
            
| 77 | 
                - repository.load(page: page)  | 
            |
| 79 | 
                + repository.loadMessageList(type, page: page)  | 
            |
| 78 | 80 | 
                .asDriver(onErrorJustReturn: NetworkArrayData<MessageListItem>.empty())  | 
            
| 79 | 81 | 
                             .drive(onNext: {[weak self] (model) in
               | 
            
| 80 | 82 | 
                                 guard let `self` = self else { return }
               | 
            
                @@ -87,7 +89,7 @@ public class MessageListViewModel {
               | 
            ||
| 87 | 89 | 
                }  | 
            
| 88 | 90 | 
                 | 
            
| 89 | 91 | 
                     public func remove(of index: Int) {
               | 
            
| 90 | 
                - repository.remove(pk: items.value[index].pk)  | 
            |
| 92 | 
                + repository.remove(type, pk: items.value[index].pk)  | 
            |
| 91 | 93 | 
                             .subscribe(onCompleted: {[weak self] in
               | 
            
| 92 | 94 | 
                                 guard let `self` = self else { return }
               | 
            
| 93 | 95 | 
                var _items = self.items.value  | 
            
                @@ -103,7 +105,7 @@ public class MessageListViewModel {
               | 
            ||
| 103 | 105 | 
                }  | 
            
| 104 | 106 | 
                 | 
            
| 105 | 107 | 
                     public func removeAll() {
               | 
            
| 106 | 
                - repository.removeAll()  | 
            |
| 108 | 
                + repository.removeAll(type)  | 
            |
| 107 | 109 | 
                             .subscribe(onCompleted: {[weak self] in
               | 
            
| 108 | 110 | 
                                 guard let `self` = self else { return }
               | 
            
| 109 | 111 | 
                self.items.accept([])  | 
            
                @@ -116,6 +118,10 @@ public class MessageListViewModel {
               | 
            ||
| 116 | 118 | 
                }.disposed(by: disposeBag)  | 
            
| 117 | 119 | 
                }  | 
            
| 118 | 120 | 
                 | 
            
| 121 | 
                +    public func readed() {
               | 
            |
| 122 | 
                +  | 
            |
| 123 | 
                + }  | 
            |
| 124 | 
                +  | 
            |
| 119 | 125 | 
                     public func didSelect(item: MessageListItem) {
               | 
            
| 120 | 126 | 
                delegate?.didSelect(item: item)  | 
            
| 121 | 127 | 
                }  | 
            
                @@ -16,7 +16,7 @@ public protocol MessageViewModelDelegate: class {
               | 
            ||
| 16 | 16 | 
                 | 
            
| 17 | 17 | 
                 public class MessageViewModel {
               | 
            
| 18 | 18 | 
                 | 
            
| 19 | 
                - private var respository: MessageRepository  | 
            |
| 19 | 
                + private var repository: MessageRepository  | 
            |
| 20 | 20 | 
                private var disposeBag = DisposeBag()  | 
            
| 21 | 21 | 
                 | 
            
| 22 | 22 | 
                public weak var delegate: MessageViewModelDelegate?  | 
            
                @@ -30,7 +30,7 @@ public class MessageViewModel {
               | 
            ||
| 30 | 30 | 
                public var thumbupBtnTapped = PublishSubject<Void>()  | 
            
| 31 | 31 | 
                 | 
            
| 32 | 32 | 
                     public init() {
               | 
            
| 33 | 
                - self.respository = MessageRepository()  | 
            |
| 33 | 
                + self.repository = MessageRepository()  | 
            |
| 34 | 34 | 
                 | 
            
| 35 | 35 | 
                         sysBtnTapped.asObservable().subscribe {[weak self] (_) in
               | 
            
| 36 | 36 | 
                             guard let `self` = self else { return }
               | 
            
                @@ -49,7 +49,7 @@ public class MessageViewModel {
               | 
            ||
| 49 | 49 | 
                }  | 
            
| 50 | 50 | 
                 | 
            
| 51 | 51 | 
                     public func reload() {
               | 
            
| 52 | 
                -        respository.load().asObservable().subscribe(onNext: {[unowned self] (items) in
               | 
            |
| 52 | 
                +        repository.loadContent().asObservable().subscribe(onNext: {[unowned self] (items) in
               | 
            |
| 53 | 53 | 
                             for item in items {
               | 
            
| 54 | 54 | 
                                 switch item.msg_type {
               | 
            
| 55 | 55 | 
                case .system:  | 
            
                @@ -7,3 +7,43 @@  | 
            ||
| 7 | 7 | 
                //  | 
            
| 8 | 8 | 
                 | 
            
| 9 | 9 | 
                import Foundation  | 
            
| 10 | 
                +import RxSwift  | 
            |
| 11 | 
                +import RxCocoa  | 
            |
| 12 | 
                +import RxDataSources  | 
            |
| 13 | 
                +  | 
            |
| 14 | 
                +public protocol PhotoDetailListViewModelSynchronization: class {
               | 
            |
| 15 | 
                + func willShow(_ item: PhotoItem)  | 
            |
| 16 | 
                +}  | 
            |
| 17 | 
                +  | 
            |
| 18 | 
                +public protocol PhotoDetailListViewModelDelegate: class {
               | 
            |
| 19 | 
                + func didSelected()  | 
            |
| 20 | 
                +}  | 
            |
| 21 | 
                +  | 
            |
| 22 | 
                +  | 
            |
| 23 | 
                +public final class PhotoDetailListViewModel {
               | 
            |
| 24 | 
                + private var items: BehaviorRelay<[PhotoItem]>  | 
            |
| 25 | 
                + public var currIndex: Int  | 
            |
| 26 | 
                +  | 
            |
| 27 | 
                + public weak var delegate: PhotoDetailListViewModelDelegate?  | 
            |
| 28 | 
                + public weak var synchronization: PhotoDetailListViewModelSynchronization?  | 
            |
| 29 | 
                +  | 
            |
| 30 | 
                +    public var content: Observable<[AnimatableSectionModel<Int, PhotoItem>]> {
               | 
            |
| 31 | 
                +        return items.map({ model in
               | 
            |
| 32 | 
                + return [AnimatableSectionModel(model: 0, items: model)]  | 
            |
| 33 | 
                + })  | 
            |
| 34 | 
                + }  | 
            |
| 35 | 
                +  | 
            |
| 36 | 
                +    public init(items: [PhotoItem], currIndex: Int) {
               | 
            |
| 37 | 
                + self.items = BehaviorRelay<[PhotoItem]>(value: items)  | 
            |
| 38 | 
                + self.currIndex = currIndex  | 
            |
| 39 | 
                + }  | 
            |
| 40 | 
                +  | 
            |
| 41 | 
                +    public func willShow(index: Int) {
               | 
            |
| 42 | 
                + currIndex = index  | 
            |
| 43 | 
                + synchronization?.willShow(items.value[currIndex])  | 
            |
| 44 | 
                + }  | 
            |
| 45 | 
                +  | 
            |
| 46 | 
                +    public func didSelected() {
               | 
            |
| 47 | 
                + delegate?.didSelected()  | 
            |
| 48 | 
                + }  | 
            |
| 49 | 
                +}  | 
            
                @@ -6,203 +6,130 @@  | 
            ||
| 6 | 6 | 
                // Copyright © 2017年 FFIB. All rights reserved.  | 
            
| 7 | 7 | 
                //  | 
            
| 8 | 8 | 
                 | 
            
| 9 | 
                -import UIKit  | 
            |
| 10 | 
                -import ObjectMapper  | 
            |
| 11 | 
                -  | 
            |
| 9 | 
                +import Foundation  | 
            |
| 10 | 
                +import RxSwift  | 
            |
| 11 | 
                +import RxCocoa  | 
            |
| 12 | 
                +import RxDataSources  | 
            |
| 12 | 13 | 
                 | 
            
| 14 | 
                +public protocol PhotoDetailViewModelDelegate: class {
               | 
            |
| 15 | 
                + func navigateToGroup(_ item: GroupItem)  | 
            |
| 16 | 
                +}  | 
            |
| 13 | 17 | 
                 | 
            
| 14 | 18 | 
                 public final class PhotoDetailViewModel {
               | 
            
| 15 | 
                - public lazy var currentPhoto = PhotoItem(json: [:])  | 
            |
| 16 | 
                - public lazy var thumbups = [thumbupUserModel]()  | 
            |
| 17 | 
                - public lazy var comments = [CommentItem]()  | 
            |
| 18 | 
                - public lazy var thumbupsCount = 0  | 
            |
| 19 | 
                - public lazy var commentsCount = 0  | 
            |
| 20 | 
                - public lazy var hdPrice: Double = -0.01  | 
            |
| 21 | 
                - public lazy var watermarkPrice: Double = -0.01  | 
            |
| 22 | 
                - var detailPageApi = NetworkApi()  | 
            |
| 23 | 
                -// var tipDelegate : TipProtocol? = nil  | 
            |
| 24 | 
                -  | 
            |
| 25 | 
                -    public init() {}
               | 
            |
| 26 | 
                -  | 
            |
| 27 | 
                -    public final func fetchThumbup(success: @escaping () -> Void) {
               | 
            |
| 28 | 
                -// let params = ["group_id": currentPhoto.group_id, "user_id": SharedUserInfo.userId, "photo_id": currentPhoto.photo_id] as [String: AnyObject]  | 
            |
| 29 | 
                -// let request = thumbupUserNetworkRequest(parameter: params)  | 
            |
| 30 | 
                -//        detailPageApi.post(request: request) {[weak self] (res) in
               | 
            |
| 31 | 
                -//            guard let weakself = self else {
               | 
            |
| 32 | 
                -// return  | 
            |
| 33 | 
                -// }  | 
            |
| 34 | 
                -// weakself.thumbups = res  | 
            |
| 35 | 
                -// weakself.thumbupsCount = res.count  | 
            |
| 36 | 
                -// success()  | 
            |
| 37 | 
                -// }  | 
            |
| 38 | 
                - }  | 
            |
| 39 | 
                -    public final func fetchComment(success: @escaping () -> Void) {
               | 
            |
| 40 | 
                -  | 
            |
| 41 | 
                -// let params = ["group_id": currentPhoto.group_id, "user_id": SharedUserInfo.userId, "photo_id": currentPhoto.photo_id] as [String: AnyObject]  | 
            |
| 42 | 
                -// let request = CommentNetworkRequest(parameter: params)  | 
            |
| 43 | 
                -//        detailPageApi.post(request: request) {[weak self] (res) in
               | 
            |
| 44 | 
                -//            guard let weakself = self else {
               | 
            |
| 45 | 
                -// return  | 
            |
| 46 | 
                -// }  | 
            |
| 47 | 
                -// weakself.comments = res  | 
            |
| 48 | 
                -// weakself.commentsCount = res.count  | 
            |
| 49 | 
                -// success()  | 
            |
| 50 | 
                -// }  | 
            |
| 19 | 
                +  | 
            |
| 20 | 
                +    public var thumbupItems: Observable<[PhotoThumbupUserItem]> {
               | 
            |
| 21 | 
                + return _thumbupItems.asObservable()  | 
            |
| 51 | 22 | 
                }  | 
            
| 52 | 
                -  | 
            |
| 53 | 
                -    public final func sendThumbup(success: @escaping () -> Void) {
               | 
            |
| 54 | 
                -// let params = ["group_id": currentPhoto.group_id, "user_id": SharedUserInfo.userId, "photo_id": currentPhoto.photo_id] as [String: AnyObject]  | 
            |
| 55 | 
                -// let request = StatusNetworkRequest(param: params, path: .thumbupSubmit)  | 
            |
| 56 | 
                -//  | 
            |
| 57 | 
                -//        detailPageApi.post(request: request) { (res) in
               | 
            |
| 58 | 
                -//            if res.message == "Duplicate Thumb Up" {
               | 
            |
| 59 | 
                -//// FFToastView.showToast(inView: UIApplication.shared.keyWindow!, withText: "照片已经点过赞了")  | 
            |
| 60 | 
                -// }  | 
            |
| 61 | 
                -//            guard res.status == 200 else {
               | 
            |
| 62 | 
                -//// FFToastView.showToast(inView: UIApplication.shared.keyWindow!, withText: "照片点赞失败")  | 
            |
| 63 | 
                -// return  | 
            |
| 64 | 
                -// }  | 
            |
| 65 | 
                -//// FFToastView.showToast(inView: UIApplication.shared.keyWindow!, withText: "照片点赞成功")  | 
            |
| 66 | 
                -// success()  | 
            |
| 67 | 
                -// }  | 
            |
| 23 | 
                +  | 
            |
| 24 | 
                +    public var commentItems: Observable<[AnimatableSectionModel<Int, PhotoCommentItem>]> {
               | 
            |
| 25 | 
                +        return _commentItems.map ({ model in
               | 
            |
| 26 | 
                + return [AnimatableSectionModel(model: 0, items: model)]  | 
            |
| 27 | 
                + })  | 
            |
| 68 | 28 | 
                }  | 
            
| 69 | 
                -  | 
            |
| 70 | 
                -    public final func sendComment(content: String, success: @escaping () -> Void) {
               | 
            |
| 71 | 
                -        guard !content.isEmpty else {
               | 
            |
| 72 | 
                - return  | 
            |
| 73 | 
                - }  | 
            |
| 74 | 
                -  | 
            |
| 75 | 
                -// let params = ["group_id": currentPhoto.group_id, "user_id": SharedUserInfo.userId, "photo_id": currentPhoto.photo_id, "comment": content] as [String: AnyObject]  | 
            |
| 76 | 
                -//  | 
            |
| 77 | 
                -// let request = StatusNetworkRequest(param: params, path: .commentSubmit)  | 
            |
| 78 | 
                -//  | 
            |
| 79 | 
                -//        detailPageApi.post(request: request) {(res) in
               | 
            |
| 80 | 
                -//            guard res.status == 200 else {
               | 
            |
| 81 | 
                -// FFToastView.showToast(inView: UIApplication.shared.keyWindow!, withText: "评论失败")  | 
            |
| 82 | 
                -// return  | 
            |
| 83 | 
                -// }  | 
            |
| 84 | 
                -// FFToastView.showToast(inView: UIApplication.shared.keyWindow!, withText: "评论成功")  | 
            |
| 85 | 
                -// success()  | 
            |
| 86 | 
                -// }  | 
            |
| 29 | 
                +  | 
            |
| 30 | 
                +    public var groupName: Observable<String> {
               | 
            |
| 31 | 
                +        return item.map({ v in
               | 
            |
| 32 | 
                + return v.group_name  | 
            |
| 33 | 
                + })  | 
            |
| 87 | 34 | 
                }  | 
            
| 88 | 
                -  | 
            |
| 89 | 
                - // MARK: pay  | 
            |
| 90 | 
                - public var orderId: String! = ""  | 
            |
| 91 | 
                -  | 
            |
| 92 | 
                -    deinit {
               | 
            |
| 93 | 
                - NotificationCenter.default.removeObserver(self)  | 
            |
| 35 | 
                +  | 
            |
| 36 | 
                +    public var groupAvatar: Observable<String> {
               | 
            |
| 37 | 
                +        return item.map({ v in
               | 
            |
| 38 | 
                + return v.group_avatar  | 
            |
| 39 | 
                + })  | 
            |
| 94 | 40 | 
                }  | 
            
| 95 | 
                -}  | 
            |
| 96 | 
                -  | 
            |
| 97 | 
                -//wechat pay  | 
            |
| 98 | 
                -extension PhotoDetailViewModel {
               | 
            |
| 99 | 
                -    public final func handleResult(errorCode: Int, success: @escaping ((_ item: PhotoItem) -> Void)) {
               | 
            |
| 100 | 
                -//        func fetchOrderDetail() {
               | 
            |
| 101 | 
                -//            detailPageApi.post(param: ["order_id": orderId, "user_id": SharedUserInfo.userId] as [String: AnyObject], url: .orderDetail) { (result) in
               | 
            |
| 102 | 
                -//                guard let status = result["status"] as? Int, let data = result["data"] as? [String: AnyObject], let photoInfo = data["group_photo_info"] as? [String: AnyObject], status == 200 else {
               | 
            |
| 103 | 
                -//// FFToastView.hideLoadingToast()  | 
            |
| 104 | 
                -//// FFToastView.showToast(inView: UIApplication.shared.keyWindow!, withText: "")  | 
            |
| 105 | 
                -// return  | 
            |
| 106 | 
                -// }  | 
            |
| 107 | 
                -// let PhotoItem = PhotoItem(map: Map(mappingType: .fromJSON, JSON: photoInfo))  | 
            |
| 108 | 
                -// self.currentPhoto.murl = PhotoItem.murl  | 
            |
| 109 | 
                -// self.currentPhoto.rurl = PhotoItem.rurl  | 
            |
| 110 | 
                -// success(PhotoItem)  | 
            |
| 111 | 
                -//// FFToastView.hideLoadingToast()  | 
            |
| 112 | 
                -//// FFToastView.showToast(inView: UIApplication.shared.keyWindow!, withText: "")  | 
            |
| 113 | 
                -//// PhotoLocalStorage.instance.updateLocalData(PhotoItem: PhotoItem)  | 
            |
| 114 | 
                -// }  | 
            |
| 115 | 
                -// }  | 
            |
| 116 | 
                -////        Delay(3) {
               | 
            |
| 117 | 
                -// let orderQequest = StatusNetworkRequest(param: ["order_id": self.orderId as AnyObject], path: .orderQuery)  | 
            |
| 118 | 
                -//            self.detailPageApi.post(request: orderQequest, handler: { (res) in
               | 
            |
| 119 | 
                -//                if res.status == 200 {
               | 
            |
| 120 | 
                -// fetchOrderDetail()  | 
            |
| 121 | 
                -//                } else {
               | 
            |
| 122 | 
                -//// FFToastView.hideLoadingToast()  | 
            |
| 123 | 
                -//// FFToastView.showToast(inView: UIApplication.shared.keyWindow!, withText: "支付失败")  | 
            |
| 124 | 
                -// }  | 
            |
| 125 | 
                -// })  | 
            |
| 126 | 
                -//// }  | 
            |
| 41 | 
                +  | 
            |
| 42 | 
                +    public var userName: Observable<String> {
               | 
            |
| 43 | 
                +        return item.map({ v in
               | 
            |
| 44 | 
                + return v.nickname  | 
            |
| 45 | 
                + })  | 
            |
| 46 | 
                + }  | 
            |
| 47 | 
                +  | 
            |
| 48 | 
                +    public var userAvatar: Observable<String> {
               | 
            |
| 49 | 
                +        return item.map({ v in
               | 
            |
| 50 | 
                + return v.avatar  | 
            |
| 51 | 
                + })  | 
            |
| 127 | 52 | 
                }  | 
            
| 53 | 
                +  | 
            |
| 54 | 
                +    public var photoTime: Observable<String> {
               | 
            |
| 55 | 
                +        return item.map({ v in
               | 
            |
| 56 | 
                + return v.create_at  | 
            |
| 57 | 
                + })  | 
            |
| 58 | 
                + }  | 
            |
| 59 | 
                +  | 
            |
| 60 | 
                +    public var thumbupCount: Observable<String> {
               | 
            |
| 61 | 
                +        return _thumbupItems.map({ v in
               | 
            |
| 62 | 
                + return "(\(v.count))"  | 
            |
| 63 | 
                + })  | 
            |
| 64 | 
                + }  | 
            |
| 65 | 
                +  | 
            |
| 66 | 
                +    public var commentCount: Observable<String> {
               | 
            |
| 67 | 
                +        return _commentItems.map({ v in
               | 
            |
| 68 | 
                + return "(\(v.count))"  | 
            |
| 69 | 
                + })  | 
            |
| 70 | 
                + }  | 
            |
| 71 | 
                +  | 
            |
| 72 | 
                +    public var canBuy: Observable<Bool> {
               | 
            |
| 73 | 
                +        return item.map({ v in
               | 
            |
| 74 | 
                + return v.display_payment_btn > 0  | 
            |
| 75 | 
                + })  | 
            |
| 76 | 
                + }  | 
            |
| 77 | 
                +  | 
            |
| 78 | 
                + public var isHiddenEnterGroupBtn = BehaviorRelay<Bool>(value: false)  | 
            |
| 79 | 
                +  | 
            |
| 80 | 
                + public var viewWillAppear = BehaviorRelay<Void>(value: ())  | 
            |
| 81 | 
                + public weak var delegate: PhotoDetailViewModelDelegate?  | 
            |
| 82 | 
                +  | 
            |
| 83 | 
                + private var item: BehaviorRelay<PhotoItem>  | 
            |
| 84 | 
                + private var _thumbupItems = BehaviorRelay<[PhotoThumbupUserItem]>(value: [])  | 
            |
| 85 | 
                + private var _commentItems = BehaviorRelay<[PhotoCommentItem]>(value: [])  | 
            |
| 128 | 86 | 
                 | 
            
| 129 | 
                -    public final func getHD(getPriceSuccess: ((_ isExist: Bool) -> Void)?) {
               | 
            |
| 130 | 
                -        if !currentPhoto.rurl.isEmpty {
               | 
            |
| 131 | 
                - getPriceSuccess!(true)  | 
            |
| 132 | 
                - return  | 
            |
| 133 | 
                -        } else {
               | 
            |
| 134 | 
                -            if hdPrice != -0.01 {
               | 
            |
| 135 | 
                - payPrice(photoType: "origin")  | 
            |
| 136 | 
                -            } else {
               | 
            |
| 137 | 
                - getPrice(photoType: "origin", success: getPriceSuccess)  | 
            |
| 138 | 
                - }  | 
            |
| 139 | 
                - }  | 
            |
| 87 | 
                + var repository: PhotoDetailRepository  | 
            |
| 88 | 
                +  | 
            |
| 89 | 
                + var disposeBag = DisposeBag()  | 
            |
| 90 | 
                +  | 
            |
| 91 | 
                +    public init(item: PhotoItem) {
               | 
            |
| 92 | 
                + self.item = BehaviorRelay<PhotoItem>(value: item)  | 
            |
| 93 | 
                + repository = PhotoDetailRepository(photoId: item.photo_id, groupId: item.group_id)  | 
            |
| 94 | 
                +  | 
            |
| 95 | 
                +        self.item.subscribe(onNext: {[unowned self] (photoItem) in
               | 
            |
| 96 | 
                + self.repository = PhotoDetailRepository(photoId: photoItem.photo_id, groupId: photoItem.group_id)  | 
            |
| 97 | 
                + self.loadCommentItems()  | 
            |
| 98 | 
                + self.loadThumbupUserItems()  | 
            |
| 99 | 
                + }).disposed(by: disposeBag)  | 
            |
| 100 | 
                + }  | 
            |
| 101 | 
                +  | 
            |
| 102 | 
                +    private func loadThumbupUserItems() {
               | 
            |
| 103 | 
                +        repository.loadThumbups().subscribe(onSuccess: { (items) in
               | 
            |
| 104 | 
                + self._thumbupItems.accept(items)  | 
            |
| 105 | 
                + }).disposed(by: disposeBag)  | 
            |
| 106 | 
                + }  | 
            |
| 107 | 
                +  | 
            |
| 108 | 
                +    private func loadCommentItems() {
               | 
            |
| 109 | 
                +        repository.loadComments().subscribe(onSuccess: { (items) in
               | 
            |
| 110 | 
                + self._commentItems.accept(items)  | 
            |
| 111 | 
                + }).disposed(by: disposeBag)  | 
            |
| 140 | 112 | 
                }  | 
            
| 141 | 113 | 
                 | 
            
| 142 | 
                -    public final func getWatermark(getPriceSuccess: ((_ isExist: Bool) -> Void)?) {
               | 
            |
| 143 | 
                -        if !currentPhoto.murl.isEmpty {
               | 
            |
| 144 | 
                - getPriceSuccess!(true)  | 
            |
| 145 | 
                - return  | 
            |
| 146 | 
                -        } else {
               | 
            |
| 147 | 
                -            if watermarkPrice != -0.01 {
               | 
            |
| 148 | 
                - payPrice(photoType: "nomark")  | 
            |
| 149 | 
                -            } else {
               | 
            |
| 150 | 
                - getPrice(photoType: "nomark", success: getPriceSuccess)  | 
            |
| 151 | 
                - }  | 
            |
| 152 | 
                - }  | 
            |
| 114 | 
                +    public final func submitThumbup() {
               | 
            |
| 115 | 
                +        repository.submitThumbup().subscribe(onSuccess: { items in
               | 
            |
| 116 | 
                + self._thumbupItems.accept(items)  | 
            |
| 117 | 
                + }).disposed(by: disposeBag)  | 
            |
| 153 | 118 | 
                }  | 
            
| 154 | 119 | 
                 | 
            
| 155 | 
                -    public final func payPrice(photoType: String) {
               | 
            |
| 156 | 
                - //下单  | 
            |
| 157 | 
                -// let body = photoType == "origin" ? "获取高清照片" : "获取去水印照片"  | 
            |
| 158 | 
                -// let price = photoType == "origin" ? hdPrice : watermarkPrice  | 
            |
| 159 | 
                -// let params = ["user_id": SharedUserInfo.userId, "body": body, "total_fee": price, "trade_type": "APP", "group_id": currentPhoto.group_id, "photo_id": currentPhoto.photo_id, "photo_type": photoType] as [String: AnyObject]  | 
            |
| 160 | 
                -//        detailPageApi.post(param: params, url: .wxorderCreat) { (result) in
               | 
            |
| 161 | 
                -//// FFToastView.hideLoadingToast()  | 
            |
| 162 | 
                -//            guard let status = result["status"] as? Int, let items = result["data"] as? [String: AnyObject], status == 200 else {
               | 
            |
| 163 | 
                -// return  | 
            |
| 164 | 
                -// }  | 
            |
| 165 | 
                -//            if let orderid = items["order_id"] as? String, let prepay_id = items["prepay_id"] as? String, let wxpay_params = items["wxpay_params"] as? [String: AnyObject], let appid = wxpay_params["appid"] as? String, let noncestr = wxpay_params["noncestr"] as? String, let package = wxpay_params["package"] as? String, let sign = wxpay_params["sign"] as? String, let partnerid = wxpay_params["partnerid"] as? String, let timestamp = wxpay_params["timestamp"] as? String {
               | 
            |
| 166 | 
                -// //支付  | 
            |
| 167 | 
                -// self.orderId = orderid  | 
            |
| 168 | 
                -// #if !((arch(i386) || arch(x86_64)))  | 
            |
| 169 | 
                -//                    guard WXApi.isWXAppInstalled() else {
               | 
            |
| 170 | 
                -// FFToastView.showToast(inView: UIApplication.shared.keyWindow!, withText: "尚未安装微信")  | 
            |
| 171 | 
                -// return  | 
            |
| 172 | 
                -// }  | 
            |
| 173 | 
                -//  | 
            |
| 174 | 
                -// WXApi.registerApp(appid)  | 
            |
| 175 | 
                -// let payRequest = PayReq()  | 
            |
| 176 | 
                -// payRequest.openID = appid  | 
            |
| 177 | 
                -// payRequest.partnerId = partnerid  | 
            |
| 178 | 
                -// payRequest.prepayId = prepay_id  | 
            |
| 179 | 
                -// payRequest.package = package  | 
            |
| 180 | 
                -// payRequest.nonceStr = noncestr  | 
            |
| 181 | 
                -// payRequest.timeStamp = UInt32(timestamp) ?? 0  | 
            |
| 182 | 
                -// payRequest.sign = sign  | 
            |
| 183 | 
                -// WXApi.send(payRequest)  | 
            |
| 184 | 
                -// #endif  | 
            |
| 185 | 
                -// }  | 
            |
| 186 | 
                -// }  | 
            |
| 120 | 
                +    public final func submitComment(text: String) {
               | 
            |
| 121 | 
                +        repository.submitComment(text: text).subscribe(onSuccess: { (items) in
               | 
            |
| 122 | 
                + self._commentItems.accept(items)  | 
            |
| 123 | 
                + }).disposed(by: disposeBag)  | 
            |
| 187 | 124 | 
                }  | 
            
| 125 | 
                +  | 
            |
| 126 | 
                +    public func navigateToGroup() {
               | 
            |
| 127 | 
                + delegate?.navigateToGroup(GroupItem(json: item.value.toJSON() as [String : AnyObject]))  | 
            |
| 128 | 
                + }  | 
            |
| 129 | 
                +}  | 
            |
| 188 | 130 | 
                 | 
            
| 189 | 
                -    public final func getPrice(photoType: String, success: ((_ isExist: Bool) -> Void)?) {
               | 
            |
| 190 | 
                -// let params = ["user_id": SharedUserInfo.userId, "photo_id": currentPhoto.photo_id, "photo_type": photoType] as [String: AnyObject]  | 
            |
| 191 | 
                -//        detailPageApi.post(param: params, url: .picPrice) {[weak self] (result) in
               | 
            |
| 192 | 
                -// guard let status = result["status"] as? Int,  | 
            |
| 193 | 
                -// let items = result["data"] as? [String: AnyObject],  | 
            |
| 194 | 
                -// status == 200,  | 
            |
| 195 | 
                -//                let weakself = self else {
               | 
            |
| 196 | 
                -// return  | 
            |
| 197 | 
                -// }  | 
            |
| 198 | 
                -//            if let price = items["price"] as? Double {
               | 
            |
| 199 | 
                -//                if photoType == "origin"{
               | 
            |
| 200 | 
                -// weakself.hdPrice = price  | 
            |
| 201 | 
                -//                } else {
               | 
            |
| 202 | 
                -// weakself.watermarkPrice = price  | 
            |
| 203 | 
                -// }  | 
            |
| 204 | 
                -// success!(false)  | 
            |
| 205 | 
                -// }  | 
            |
| 206 | 
                -// }  | 
            |
| 131 | 
                +extension PhotoDetailViewModel: PhotoDetailListViewModelSynchronization {
               | 
            |
| 132 | 
                +    public func willShow(_ item: PhotoItem) {
               | 
            |
| 133 | 
                + self.item.accept(item)  | 
            |
| 207 | 134 | 
                }  | 
            
| 208 | 135 | 
                }  | 
            
                @@ -7,3 +7,116 @@  | 
            ||
| 7 | 7 | 
                //  | 
            
| 8 | 8 | 
                 | 
            
| 9 | 9 | 
                import Foundation  | 
            
| 10 | 
                +  | 
            |
| 11 | 
                +//wechat pay  | 
            |
| 12 | 
                +extension PhotoDetailViewModel {
               | 
            |
| 13 | 
                +    public final func handleResult(errorCode: Int, success: @escaping ((_ item: PhotoItem) -> Void)) {
               | 
            |
| 14 | 
                +        //        func fetchOrderDetail() {
               | 
            |
| 15 | 
                +        //            detailPageApi.post(param: ["order_id": orderId, "user_id": SharedUserInfo.userId] as [String: AnyObject], url: .orderDetail) { (result) in
               | 
            |
| 16 | 
                +        //                guard let status = result["status"] as? Int, let data = result["data"] as? [String: AnyObject], let photoInfo = data["group_photo_info"] as? [String: AnyObject], status == 200 else {
               | 
            |
| 17 | 
                + //// FFToastView.hideLoadingToast()  | 
            |
| 18 | 
                + //// FFToastView.showToast(inView: UIApplication.shared.keyWindow!, withText: "")  | 
            |
| 19 | 
                + // return  | 
            |
| 20 | 
                + // }  | 
            |
| 21 | 
                + // let PhotoItem = PhotoItem(map: Map(mappingType: .fromJSON, JSON: photoInfo))  | 
            |
| 22 | 
                + // self.currentPhoto.murl = PhotoItem.murl  | 
            |
| 23 | 
                + // self.currentPhoto.rurl = PhotoItem.rurl  | 
            |
| 24 | 
                + // success(PhotoItem)  | 
            |
| 25 | 
                + //// FFToastView.hideLoadingToast()  | 
            |
| 26 | 
                + //// FFToastView.showToast(inView: UIApplication.shared.keyWindow!, withText: "")  | 
            |
| 27 | 
                + //// PhotoLocalStorage.instance.updateLocalData(PhotoItem: PhotoItem)  | 
            |
| 28 | 
                + // }  | 
            |
| 29 | 
                + // }  | 
            |
| 30 | 
                +        ////        Delay(3) {
               | 
            |
| 31 | 
                + // let orderQequest = StatusNetworkRequest(param: ["order_id": self.orderId as AnyObject], path: .orderQuery)  | 
            |
| 32 | 
                +        //            self.detailPageApi.post(request: orderQequest, handler: { (res) in
               | 
            |
| 33 | 
                +        //                if res.status == 200 {
               | 
            |
| 34 | 
                + // fetchOrderDetail()  | 
            |
| 35 | 
                +        //                } else {
               | 
            |
| 36 | 
                + //// FFToastView.hideLoadingToast()  | 
            |
| 37 | 
                + //// FFToastView.showToast(inView: UIApplication.shared.keyWindow!, withText: "支付失败")  | 
            |
| 38 | 
                + // }  | 
            |
| 39 | 
                + // })  | 
            |
| 40 | 
                + //// }  | 
            |
| 41 | 
                + }  | 
            |
| 42 | 
                +  | 
            |
| 43 | 
                +    public final func getHD(getPriceSuccess: ((_ isExist: Bool) -> Void)?) {
               | 
            |
| 44 | 
                +        //        if !currentPhoto.rurl.isEmpty {
               | 
            |
| 45 | 
                + // getPriceSuccess!(true)  | 
            |
| 46 | 
                + // return  | 
            |
| 47 | 
                +        //        } else {
               | 
            |
| 48 | 
                +        //            if hdPrice != -0.01 {
               | 
            |
| 49 | 
                + // payPrice(photoType: "origin")  | 
            |
| 50 | 
                +        //            } else {
               | 
            |
| 51 | 
                + // getPrice(photoType: "origin", success: getPriceSuccess)  | 
            |
| 52 | 
                + // }  | 
            |
| 53 | 
                + // }  | 
            |
| 54 | 
                + }  | 
            |
| 55 | 
                +  | 
            |
| 56 | 
                +    public final func getWatermark(getPriceSuccess: ((_ isExist: Bool) -> Void)?) {
               | 
            |
| 57 | 
                +        //        if !currentPhoto.murl.isEmpty {
               | 
            |
| 58 | 
                + // getPriceSuccess!(true)  | 
            |
| 59 | 
                + // return  | 
            |
| 60 | 
                +        //        } else {
               | 
            |
| 61 | 
                +        //            if watermarkPrice != -0.01 {
               | 
            |
| 62 | 
                + // payPrice(photoType: "nomark")  | 
            |
| 63 | 
                +        //            } else {
               | 
            |
| 64 | 
                + // getPrice(photoType: "nomark", success: getPriceSuccess)  | 
            |
| 65 | 
                + // }  | 
            |
| 66 | 
                + // }  | 
            |
| 67 | 
                + }  | 
            |
| 68 | 
                +  | 
            |
| 69 | 
                +    public final func payPrice(photoType: String) {
               | 
            |
| 70 | 
                + //下单  | 
            |
| 71 | 
                + // let body = photoType == "origin" ? "获取高清照片" : "获取去水印照片"  | 
            |
| 72 | 
                + // let price = photoType == "origin" ? hdPrice : watermarkPrice  | 
            |
| 73 | 
                + // let params = ["user_id": SharedUserInfo.userId, "body": body, "total_fee": price, "trade_type": "APP", "group_id": currentPhoto.group_id, "photo_id": currentPhoto.photo_id, "photo_type": photoType] as [String: AnyObject]  | 
            |
| 74 | 
                +        //        detailPageApi.post(param: params, url: .wxorderCreat) { (result) in
               | 
            |
| 75 | 
                + //// FFToastView.hideLoadingToast()  | 
            |
| 76 | 
                +        //            guard let status = result["status"] as? Int, let items = result["data"] as? [String: AnyObject], status == 200 else {
               | 
            |
| 77 | 
                + // return  | 
            |
| 78 | 
                + // }  | 
            |
| 79 | 
                +        //            if let orderid = items["order_id"] as? String, let prepay_id = items["prepay_id"] as? String, let wxpay_params = items["wxpay_params"] as? [String: AnyObject], let appid = wxpay_params["appid"] as? String, let noncestr = wxpay_params["noncestr"] as? String, let package = wxpay_params["package"] as? String, let sign = wxpay_params["sign"] as? String, let partnerid = wxpay_params["partnerid"] as? String, let timestamp = wxpay_params["timestamp"] as? String {
               | 
            |
| 80 | 
                + // //支付  | 
            |
| 81 | 
                + // self.orderId = orderid  | 
            |
| 82 | 
                + // #if !((arch(i386) || arch(x86_64)))  | 
            |
| 83 | 
                +        //                    guard WXApi.isWXAppInstalled() else {
               | 
            |
| 84 | 
                + // FFToastView.showToast(inView: UIApplication.shared.keyWindow!, withText: "尚未安装微信")  | 
            |
| 85 | 
                + // return  | 
            |
| 86 | 
                + // }  | 
            |
| 87 | 
                + //  | 
            |
| 88 | 
                + // WXApi.registerApp(appid)  | 
            |
| 89 | 
                + // let payRequest = PayReq()  | 
            |
| 90 | 
                + // payRequest.openID = appid  | 
            |
| 91 | 
                + // payRequest.partnerId = partnerid  | 
            |
| 92 | 
                + // payRequest.prepayId = prepay_id  | 
            |
| 93 | 
                + // payRequest.package = package  | 
            |
| 94 | 
                + // payRequest.nonceStr = noncestr  | 
            |
| 95 | 
                + // payRequest.timeStamp = UInt32(timestamp) ?? 0  | 
            |
| 96 | 
                + // payRequest.sign = sign  | 
            |
| 97 | 
                + // WXApi.send(payRequest)  | 
            |
| 98 | 
                + // #endif  | 
            |
| 99 | 
                + // }  | 
            |
| 100 | 
                + // }  | 
            |
| 101 | 
                + }  | 
            |
| 102 | 
                +  | 
            |
| 103 | 
                +    public final func getPrice(photoType: String, success: ((_ isExist: Bool) -> Void)?) {
               | 
            |
| 104 | 
                + // let params = ["user_id": SharedUserInfo.userId, "photo_id": currentPhoto.photo_id, "photo_type": photoType] as [String: AnyObject]  | 
            |
| 105 | 
                +        //        detailPageApi.post(param: params, url: .picPrice) {[weak self] (result) in
               | 
            |
| 106 | 
                + // guard let status = result["status"] as? Int,  | 
            |
| 107 | 
                + // let items = result["data"] as? [String: AnyObject],  | 
            |
| 108 | 
                + // status == 200,  | 
            |
| 109 | 
                +        //                let weakself = self else {
               | 
            |
| 110 | 
                + // return  | 
            |
| 111 | 
                + // }  | 
            |
| 112 | 
                +        //            if let price = items["price"] as? Double {
               | 
            |
| 113 | 
                +        //                if photoType == "origin"{
               | 
            |
| 114 | 
                + // weakself.hdPrice = price  | 
            |
| 115 | 
                +        //                } else {
               | 
            |
| 116 | 
                + // weakself.watermarkPrice = price  | 
            |
| 117 | 
                + // }  | 
            |
| 118 | 
                + // success!(false)  | 
            |
| 119 | 
                + // }  | 
            |
| 120 | 
                + // }  | 
            |
| 121 | 
                + }  | 
            |
| 122 | 
                +}  | 
            
                @@ -8,12 +8,13 @@  | 
            ||
| 8 | 8 | 
                 | 
            
| 9 | 9 | 
                import Foundation  | 
            
| 10 | 10 | 
                import RxSwift  | 
            
| 11 | 
                +import RxCocoa  | 
            |
| 11 | 12 | 
                 | 
            
| 12 | 13 | 
                fileprivate(set) var ShareUserId: String = ""  | 
            
| 13 | 14 | 
                 | 
            
| 14 | 15 | 
                 public class UserInfoViewModel {
               | 
            
| 15 | 16 | 
                 | 
            
| 16 | 
                - public var shareUserInfo = BehaviorSubject<UserInfo>(value: UserInfo())  | 
            |
| 17 | 
                + public var shareUserInfo = BehaviorRelay<UserInfo>(value: UserInfo())  | 
            |
| 17 | 18 | 
                 | 
            
| 18 | 19 | 
                     public var isLoggedIn: Observable<Void> {
               | 
            
| 19 | 20 | 
                return shareUserInfo.asObservable()  | 
            
                @@ -63,12 +64,12 @@ public class UserInfoViewModel {
               | 
            ||
| 63 | 64 | 
                }  | 
            
| 64 | 65 | 
                 | 
            
| 65 | 66 | 
                     fileprivate func load() {
               | 
            
| 66 | 
                - shareUserInfo.onNext(repository.readUserInfo())  | 
            |
| 67 | 
                + shareUserInfo.accept(repository.readUserInfo())  | 
            |
| 67 | 68 | 
                }  | 
            
| 68 | 69 | 
                 | 
            
| 69 | 70 | 
                     public func guestLogin() {
               | 
            
| 70 | 71 | 
                         repository.guestLogin().subscribe(onSuccess: { (userInfo) in
               | 
            
| 71 | 
                - self.shareUserInfo.onNext(userInfo)  | 
            |
| 72 | 
                + self.shareUserInfo.accept(userInfo)  | 
            |
| 72 | 73 | 
                self._loginCompleted.onNext(())  | 
            
| 73 | 74 | 
                         }) { (error) in
               | 
            
| 74 | 75 | 
                             #warning("错误处理")
               | 
            
                @@ -77,7 +78,7 @@ public class UserInfoViewModel {
               | 
            ||
| 77 | 78 | 
                 | 
            
| 78 | 79 | 
                     public func wxLogin() {
               | 
            
| 79 | 80 | 
                         repository.guestLogin().subscribe(onSuccess: { (userInfo) in
               | 
            
| 80 | 
                - self.shareUserInfo.onNext(userInfo)  | 
            |
| 81 | 
                + self.shareUserInfo.accept(userInfo)  | 
            |
| 81 | 82 | 
                self._loginCompleted.onNext(())  | 
            
| 82 | 83 | 
                         }) { (error) in
               | 
            
| 83 | 84 | 
                             #warning("错误处理")
               | 
            
                @@ -104,8 +104,8 @@ extension ArrayUserDefaultable where ArrayDefaultKey.RawValue == String {
               | 
            ||
| 104 | 104 | 
                         guard let value = UserDefaults.standard.array(forKey: key) as? [[String: AnyObject]] else {
               | 
            
| 105 | 105 | 
                return []  | 
            
| 106 | 106 | 
                }  | 
            
| 107 | 
                -        let items = value.flatMap { Item.init(value: $0) }
               | 
            |
| 108 | 
                - return items ?? [Item]()  | 
            |
| 107 | 
                +        let items = value.compactMap { Item.init(value: $0) }
               | 
            |
| 108 | 
                + return items  | 
            |
| 109 | 109 | 
                }  | 
            
| 110 | 110 | 
                }  | 
            
| 111 | 111 | 
                 | 
            
                @@ -46,5 +46,10 @@ public extension UIImage {
               | 
            ||
| 46 | 46 | 
                }  | 
            
| 47 | 47 | 
                }  | 
            
| 48 | 48 | 
                 | 
            
| 49 | 
                -  | 
            |
| 49 | 
                +    struct PhotoDetail {
               | 
            |
| 50 | 
                +        public static var purchaseBackground: UIImage? {
               | 
            |
| 51 | 
                + return UIImage(named: "purchase-background")?.resizableImage(withCapInsets: UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0),  | 
            |
| 52 | 
                + resizingMode: .stretch)  | 
            |
| 53 | 
                + }  | 
            |
| 54 | 
                + }  | 
            |
| 50 | 55 | 
                }  | 
            
                @@ -10,17 +10,7 @@ import UIKit  | 
            ||
| 10 | 10 | 
                 | 
            
| 11 | 11 | 
                 extension UITextField {
               | 
            
| 12 | 12 | 
                 | 
            
| 13 | 
                -//    public var isEmpty: Bool{
               | 
            |
| 14 | 
                -// return text?.isEmpty ?? false  | 
            |
| 15 | 
                -// }  | 
            |
| 16 | 
                -  | 
            |
| 17 | 
                -//    public var isPhoneNumber: Bool {
               | 
            |
| 18 | 
                -// return text?.isPhoneNumber ?? false  | 
            |
| 19 | 
                -// }  | 
            |
| 20 | 
                -  | 
            |
| 21 | 
                -//    public var isEmail: Bool {
               | 
            |
| 22 | 
                -// return text?.isEmail ?? false  | 
            |
| 23 | 
                -// }  | 
            |
| 13 | 
                +    public var isEmpty: Bool { return text?.isEmpty ?? false }
               | 
            |
| 24 | 14 | 
                 | 
            
| 25 | 15 | 
                     public func setPlaceHolderTextColor(_ color: UIColor) {
               | 
            
| 26 | 16 | 
                         guard let holder = placeholder, !holder.isEmpty else {
               | 
            
                @@ -11,7 +11,7 @@ import UIKit  | 
            ||
| 11 | 11 | 
                //  | 
            
| 12 | 12 | 
                 extension UITextView {
               | 
            
| 13 | 13 | 
                 | 
            
| 14 | 
                -    public var isEmpty: Bool{
               | 
            |
| 14 | 
                +    public var isEmpty: Bool {
               | 
            |
| 15 | 15 | 
                return text?.isEmpty ?? false  | 
            
| 16 | 16 | 
                }  | 
            
| 17 | 17 | 
                 | 
            
                @@ -113,11 +113,11 @@ public final class AlertView: UIView {
               | 
            ||
| 113 | 113 | 
                 | 
            
| 114 | 114 | 
                     private func installTarget() {
               | 
            
| 115 | 115 | 
                         if cancelAction != nil {
               | 
            
| 116 | 
                - cancelItem.addTarget(self, action: #selector(cancelAction(btn:)), for: .touchDown)  | 
            |
| 116 | 
                + cancelItem.addTarget(self, action: #selector(cancelAction(btn:)), for: .touchUpInside)  | 
            |
| 117 | 117 | 
                }  | 
            
| 118 | 118 | 
                 | 
            
| 119 | 119 | 
                         if confirmAction != nil {
               | 
            
| 120 | 
                - confirmItem.addTarget(self, action: #selector(confirmAction(btn:)), for: .touchDown)  | 
            |
| 120 | 
                + confirmItem.addTarget(self, action: #selector(confirmAction(btn:)), for: .touchUpInside)  | 
            |
| 121 | 121 | 
                }  | 
            
| 122 | 122 | 
                }  | 
            
| 123 | 123 | 
                 | 
            
                @@ -219,7 +219,7 @@ fileprivate extension AlertView {
               | 
            ||
| 219 | 219 | 
                NSLayoutConstraint.activate([  | 
            
| 220 | 220 | 
                label.leadingAnchor.constraint(equalTo: layoutMarginsGuide.leadingAnchor),  | 
            
| 221 | 221 | 
                label.trailingAnchor.constraint(equalTo: layoutMarginsGuide.trailingAnchor),  | 
            
| 222 | 
                - label.topAnchor.constraint(equalTo: last?.bottomAnchor ?? layoutMarginsGuide.topAnchor, constant: 6),  | 
            |
| 222 | 
                + label.topAnchor.constraint(equalTo: last?.bottomAnchor ?? layoutMarginsGuide.topAnchor, constant: 12),  | 
            |
| 223 | 223 | 
                ])  | 
            
| 224 | 224 | 
                 | 
            
| 225 | 225 | 
                last = label  | 
            
                @@ -47,7 +47,6 @@ extension UIViewController {
               | 
            ||
| 47 | 47 | 
                 | 
            
| 48 | 48 | 
                         guard gesture.state == .ended else { return }
               | 
            
| 49 | 49 | 
                 | 
            
| 50 | 
                -        for vc in navigationController?.viewControllers ?? [] { print(vc) }
               | 
            |
| 51 | 50 | 
                if (percentage > 0.5 && navigationController == nil) ||  | 
            
| 52 | 51 | 
                             (percentage < 0.5 && navigationController?.visibleViewController == self) {
               | 
            
| 53 | 52 | 
                fadeOutAnimation()  | 
            
                @@ -6,7 +6,7 @@  | 
            ||
| 6 | 6 | 
                // Copyright © 2018 yb. All rights reserved.  | 
            
| 7 | 7 | 
                //  | 
            
| 8 | 8 | 
                 | 
            
| 9 | 
                -import Foundation  | 
            |
| 9 | 
                +import UIKit  | 
            |
| 10 | 10 | 
                import PaiaiDataKit  | 
            
| 11 | 11 | 
                import PaiaiUIKit  | 
            
| 12 | 12 | 
                 | 
            
                @@ -45,7 +45,9 @@ public final class AppCoordinator {
               | 
            ||
| 45 | 45 | 
                PageItem(title: "消息",  | 
            
| 46 | 46 | 
                viewController: messageVC)]  | 
            
| 47 | 47 | 
                 | 
            
| 48 | 
                - let homeCoordinator = HomeCoordinator(homeVC, userInfoViewModel: shareUserInfoViewModel)  | 
            |
| 48 | 
                + let homeCoordinator = HomeCoordinator(homeVC,  | 
            |
| 49 | 
                + navigationController: navigationController,  | 
            |
| 50 | 
                + userInfoViewModel: shareUserInfoViewModel)  | 
            |
| 49 | 51 | 
                let messageCoordinator = MessageCoordinator(messageVC,  | 
            
| 50 | 52 | 
                navigationController: navigationController,  | 
            
| 51 | 53 | 
                userInfoViewModel: shareUserInfoViewModel)  | 
            
                @@ -44,6 +44,7 @@ public final class ContainerViewController: PageViewController {
               | 
            ||
| 44 | 44 | 
                     private var navigationContentView: UIView = {
               | 
            
| 45 | 45 | 
                let contentView = UIView(frame: CGRect(x: 0, y: 0, width: 50, height: 32))  | 
            
| 46 | 46 | 
                return contentView  | 
            
| 47 | 
                +  | 
            |
| 47 | 48 | 
                }()  | 
            
| 48 | 49 | 
                 | 
            
| 49 | 50 | 
                /// life circle  | 
            
                @@ -14,27 +14,45 @@ class GroupCoordinator: Coordinator {
               | 
            ||
| 14 | 14 | 
                let navigationController: UINavigationController  | 
            
| 15 | 15 | 
                let groupViewController: GroupViewController  | 
            
| 16 | 16 | 
                 | 
            
| 17 | 
                + var coordinators: [String: Coordinator] = [:]  | 
            |
| 18 | 
                +  | 
            |
| 17 | 19 | 
                     init(_ groupVC: GroupViewController, navigationController: UINavigationController) {
               | 
            
| 18 | 20 | 
                self.groupViewController = groupVC  | 
            
| 19 | 21 | 
                self.navigationController = navigationController  | 
            
| 20 | 22 | 
                 | 
            
| 21 | 23 | 
                groupViewController.viewModel.delegate = self  | 
            
| 24 | 
                +  | 
            |
| 22 | 25 | 
                }  | 
            
| 23 | 26 | 
                }  | 
            
| 24 | 27 | 
                 | 
            
| 25 | 28 | 
                 extension GroupCoordinator: GroupViewModelDelegate {
               | 
            
| 26 | 
                -    func navigateToGroupDetail() {
               | 
            |
| 29 | 
                +    func navigateToGroupDetail(_ item: GroupItem) {
               | 
            |
| 30 | 
                + let coordinator = GroupDetailCoordinator(makeGroupDetailViewController(item), navigationController: navigationController)  | 
            |
| 31 | 
                + coordinators["groupDetail"] = coordinator  | 
            |
| 27 | 32 | 
                 | 
            
| 33 | 
                + navigationController.pushViewController(coordinator.groupDetailViewController)  | 
            |
| 28 | 34 | 
                }  | 
            
| 29 | 35 | 
                 | 
            
| 30 | 
                -    func didSelect(_ item: PhotoItem) {
               | 
            |
| 31 | 
                -  | 
            |
| 36 | 
                +    func didSelect(_ items: [PhotoItem], currIndex: Int) {
               | 
            |
| 37 | 
                + let ctl = UIStoryboard.photoDetail.instantiateController(PhotoDetailViewController.self)  | 
            |
| 38 | 
                + let viewModel = PhotoDetailViewModel(item: items[currIndex])  | 
            |
| 39 | 
                + viewModel.isHiddenEnterGroupBtn.accept(true)  | 
            |
| 40 | 
                + let coordinator = PhotoDetailCoordinator(ctl, nav: navigationController,  | 
            |
| 41 | 
                + viewModel: viewModel,  | 
            |
| 42 | 
                + listViewModel: PhotoDetailListViewModel(items: items, currIndex: currIndex))  | 
            |
| 43 | 
                + coordinators["photoDetail"] = coordinator  | 
            |
| 44 | 
                + coordinator.start()  | 
            |
| 45 | 
                + navigationController.pushViewController(coordinator.photoDetailViewController)  | 
            |
| 32 | 46 | 
                }  | 
            
| 33 | 47 | 
                }  | 
            
| 34 | 48 | 
                 | 
            
| 35 | 49 | 
                 fileprivate extension GroupCoordinator {
               | 
            
| 36 | 
                -    func makeGroupDetailViewController() {
               | 
            |
| 50 | 
                + func makeGroupDetailViewController(_ item: GroupItem) -> GroupDetailViewController  | 
            |
| 51 | 
                +    {
               | 
            |
| 52 | 
                + let vc = UIStoryboard.groupDetail.instantiateController(GroupDetailViewController.self)  | 
            |
| 53 | 
                + vc.viewModel = GroupDetailViewModel(item: item)  | 
            |
| 37 | 54 | 
                 | 
            
| 55 | 
                + return vc  | 
            |
| 38 | 56 | 
                }  | 
            
| 39 | 57 | 
                }  | 
            
| 40 | 58 | 
                 | 
            
                @@ -1,7 +1,12 @@  | 
            ||
| 1 | 1 | 
                <?xml version="1.0" encoding="UTF-8"?>  | 
            
| 2 | 
                -<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14460.31" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" colorMatched="YES" initialViewController="s9X-RR-Rat">  | 
            |
| 2 | 
                +<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14460.31" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useSafeAreas="YES" colorMatched="YES">  | 
            |
| 3 | 
                + <device id="retina4_7" orientation="portrait">  | 
            |
| 4 | 
                + <adaptation id="fullscreen"/>  | 
            |
| 5 | 
                + </device>  | 
            |
| 3 | 6 | 
                <dependencies>  | 
            
| 7 | 
                + <deployment identifier="iOS"/>  | 
            |
| 4 | 8 | 
                <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14460.20"/>  | 
            
| 9 | 
                + <capability name="Safe area layout guides" minToolsVersion="9.0"/>  | 
            |
| 5 | 10 | 
                <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>  | 
            
| 6 | 11 | 
                </dependencies>  | 
            
| 7 | 12 | 
                <scenes>  | 
            
                @@ -9,10 +14,6 @@  | 
            ||
| 9 | 14 | 
                <scene sceneID="XYC-ye-yVT">  | 
            
| 10 | 15 | 
                <objects>  | 
            
| 11 | 16 | 
                <viewController storyboardIdentifier="ShowGroupQRController" automaticallyAdjustsScrollViewInsets="NO" id="1xf-Gx-gQ6" userLabel="ShowGroupQRController" customClass="ShowGroupQRController" customModule="PaiAi" sceneMemberID="viewController">  | 
            
| 12 | 
                - <layoutGuides>  | 
            |
| 13 | 
                - <viewControllerLayoutGuide type="top" id="VlO-HE-vXU"/>  | 
            |
| 14 | 
                - <viewControllerLayoutGuide type="bottom" id="rXV-YC-UCZ"/>  | 
            |
| 15 | 
                - </layoutGuides>  | 
            |
| 16 | 17 | 
                <view key="view" contentMode="scaleToFill" id="ZBk-gn-qqZ">  | 
            
| 17 | 18 | 
                <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>  | 
            
| 18 | 19 | 
                <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>  | 
            
                @@ -74,9 +75,10 @@  | 
            ||
| 74 | 75 | 
                <constraints>  | 
            
| 75 | 76 | 
                <constraint firstItem="3Yp-sn-LQg" firstAttribute="centerX" secondItem="omt-Jt-Qr4" secondAttribute="centerX" id="5jg-XD-1je"/>  | 
            
| 76 | 77 | 
                <constraint firstItem="AOa-xP-S2e" firstAttribute="centerY" secondItem="ZBk-gn-qqZ" secondAttribute="centerY" constant="-20" id="gqp-We-1FY"/>  | 
            
| 77 | 
                - <constraint firstItem="AOa-xP-S2e" firstAttribute="centerX" secondItem="ZBk-gn-qqZ" secondAttribute="centerX" id="ou7-87-DCL"/>  | 
            |
| 78 | 
                + <constraint firstItem="AOa-xP-S2e" firstAttribute="centerX" secondItem="x9Y-Y7-7ge" secondAttribute="centerX" id="ou7-87-DCL"/>  | 
            |
| 78 | 79 | 
                <constraint firstItem="3Yp-sn-LQg" firstAttribute="top" secondItem="omt-Jt-Qr4" secondAttribute="bottom" constant="12" id="vwi-7r-nUU"/>  | 
            
| 79 | 80 | 
                </constraints>  | 
            
| 81 | 
                + <viewLayoutGuide key="safeArea" id="x9Y-Y7-7ge"/>  | 
            |
| 80 | 82 | 
                <connections>  | 
            
| 81 | 83 | 
                <outletCollection property="gestureRecognizers" destination="qe1-cB-TmI" appends="YES" id="9kM-Mf-00B"/>  | 
            
| 82 | 84 | 
                </connections>  | 
            
                @@ -101,15 +103,11 @@  | 
            ||
| 101 | 103 | 
                <scene sceneID="Oa4-Yi-HJu">  | 
            
| 102 | 104 | 
                <objects>  | 
            
| 103 | 105 | 
                <viewController storyboardIdentifier="GroupDetailViewController" id="s9X-RR-Rat" userLabel="GroupDetailViewController" customClass="GroupDetailViewController" customModule="Paiai_iOS" customModuleProvider="target" sceneMemberID="viewController">  | 
            
| 104 | 
                - <layoutGuides>  | 
            |
| 105 | 
                - <viewControllerLayoutGuide type="top" id="w38-w0-jLd"/>  | 
            |
| 106 | 
                - <viewControllerLayoutGuide type="bottom" id="a7q-m3-cDV"/>  | 
            |
| 107 | 
                - </layoutGuides>  | 
            |
| 108 | 106 | 
                <view key="view" contentMode="scaleToFill" id="OXa-NJ-XOO">  | 
            
| 109 | 107 | 
                <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>  | 
            
| 110 | 108 | 
                <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>  | 
            
| 111 | 109 | 
                <subviews>  | 
            
| 112 | 
                - <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="fpL-PF-0xo">  | 
            |
| 110 | 
                + <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="fpL-PF-0xo" userLabel="Group Name">  | 
            |
| 113 | 111 | 
                <rect key="frame" x="0.0" y="25" width="375" height="45"/>  | 
            
| 114 | 112 | 
                <subviews>  | 
            
| 115 | 113 | 
                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="群名称" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="NME-fp-tEb">  | 
            
                @@ -119,95 +117,91 @@  | 
            ||
| 119 | 117 | 
                <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>  | 
            
| 120 | 118 | 
                <nil key="highlightedColor"/>  | 
            
| 121 | 119 | 
                </label>  | 
            
| 122 | 
                - <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="列表箭头" translatesAutoresizingMaskIntoConstraints="NO" id="7Hg-xN-Smd">  | 
            |
| 123 | 
                - <rect key="frame" x="339" y="4.5" width="24" height="36"/>  | 
            |
| 124 | 
                - </imageView>  | 
            |
| 125 | 
                - <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="名" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="1X6-D5-hkj">  | 
            |
| 126 | 
                - <rect key="frame" x="312" y="12.5" width="17" height="20"/>  | 
            |
| 120 | 
                + <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="1X6-D5-hkj">  | 
            |
| 121 | 
                + <rect key="frame" x="329" y="22.5" width="0.0" height="0.0"/>  | 
            |
| 127 | 122 | 
                <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>  | 
            
| 128 | 123 | 
                <fontDescription key="fontDescription" type="system" pointSize="16"/>  | 
            
| 129 | 124 | 
                <color key="textColor" red="0.59999999999999998" green="0.59999999999999998" blue="0.59999999999999998" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>  | 
            
| 130 | 125 | 
                <nil key="highlightedColor"/>  | 
            
| 131 | 126 | 
                </label>  | 
            
| 132 | 
                - <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="eaB-II-BjR">  | 
            |
| 133 | 
                - <rect key="frame" x="0.0" y="0.0" width="375" height="45"/>  | 
            |
| 134 | 
                - <connections>  | 
            |
| 135 | 
                - <segue destination="ahh-gm-C2t" kind="modal" id="OpJ-RB-GhS"/>  | 
            |
| 136 | 
                - </connections>  | 
            |
| 137 | 
                - </button>  | 
            |
| 138 | 
                - <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="NP3-gL-4Lm">  | 
            |
| 139 | 
                - <rect key="frame" x="0.0" y="44.5" width="375" height="0.5"/>  | 
            |
| 140 | 
                - <color key="backgroundColor" red="0.90588235289999997" green="0.90588235289999997" blue="0.90588235289999997" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>  | 
            |
| 141 | 
                - <constraints>  | 
            |
| 142 | 
                - <constraint firstAttribute="height" constant="0.5" id="2p1-dV-Xd4"/>  | 
            |
| 143 | 
                - </constraints>  | 
            |
| 144 | 
                - </view>  | 
            |
| 127 | 
                + <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="list-arrow" translatesAutoresizingMaskIntoConstraints="NO" id="7Hg-xN-Smd">  | 
            |
| 128 | 
                + <rect key="frame" x="339" y="4.5" width="24" height="36"/>  | 
            |
| 129 | 
                + </imageView>  | 
            |
| 145 | 130 | 
                </subviews>  | 
            
| 146 | 131 | 
                <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>  | 
            
| 132 | 
                + <gestureRecognizers/>  | 
            |
| 147 | 133 | 
                <constraints>  | 
            
| 148 | 
                - <constraint firstItem="eaB-II-BjR" firstAttribute="top" secondItem="fpL-PF-0xo" secondAttribute="top" id="AfI-TX-MBT"/>  | 
            |
| 149 | 
                - <constraint firstItem="NP3-gL-4Lm" firstAttribute="leading" secondItem="fpL-PF-0xo" secondAttribute="leading" id="Mkh-ez-jmF"/>  | 
            |
| 150 | 134 | 
                <constraint firstItem="7Hg-xN-Smd" firstAttribute="centerY" secondItem="fpL-PF-0xo" secondAttribute="centerY" id="Rjv-h5-Wtq"/>  | 
            
| 151 | 135 | 
                <constraint firstAttribute="height" constant="45" id="UPg-bK-pto"/>  | 
            
| 152 | 
                - <constraint firstAttribute="trailing" secondItem="eaB-II-BjR" secondAttribute="trailing" id="Wd9-LL-kRx"/>  | 
            |
| 153 | 136 | 
                <constraint firstItem="NME-fp-tEb" firstAttribute="centerY" secondItem="fpL-PF-0xo" secondAttribute="centerY" id="X0F-x5-Iql"/>  | 
            
| 154 | 137 | 
                <constraint firstItem="NME-fp-tEb" firstAttribute="leading" secondItem="fpL-PF-0xo" secondAttribute="leading" constant="12" id="Znr-w6-kFQ"/>  | 
            
| 155 | 138 | 
                <constraint firstItem="7Hg-xN-Smd" firstAttribute="leading" secondItem="1X6-D5-hkj" secondAttribute="trailing" constant="10" id="qjJ-vN-hzP"/>  | 
            
| 156 | 139 | 
                <constraint firstAttribute="trailing" secondItem="7Hg-xN-Smd" secondAttribute="trailing" constant="12" id="tEJ-5a-H97"/>  | 
            
| 157 | 
                - <constraint firstAttribute="bottom" secondItem="eaB-II-BjR" secondAttribute="bottom" id="tMA-ex-sLV"/>  | 
            |
| 158 | 
                - <constraint firstAttribute="trailing" secondItem="NP3-gL-4Lm" secondAttribute="trailing" id="tRS-n4-IKl"/>  | 
            |
| 159 | 
                - <constraint firstAttribute="bottom" secondItem="NP3-gL-4Lm" secondAttribute="bottom" id="tiZ-Os-N8E"/>  | 
            |
| 160 | 140 | 
                <constraint firstItem="1X6-D5-hkj" firstAttribute="centerY" secondItem="fpL-PF-0xo" secondAttribute="centerY" id="v6h-VQ-qa8"/>  | 
            
| 161 | 
                - <constraint firstItem="eaB-II-BjR" firstAttribute="leading" secondItem="fpL-PF-0xo" secondAttribute="leading" id="yWU-Jg-dGJ"/>  | 
            |
| 162 | 141 | 
                </constraints>  | 
            
| 142 | 
                + <connections>  | 
            |
| 143 | 
                + <outletCollection property="gestureRecognizers" destination="QhO-Be-7C1" appends="YES" id="9lj-Za-c71"/>  | 
            |
| 144 | 
                + </connections>  | 
            |
| 163 | 145 | 
                </view>  | 
            
| 164 | 
                - <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="pMy-uJ-dNy">  | 
            |
| 165 | 
                - <rect key="frame" x="0.0" y="70" width="375" height="45"/>  | 
            |
| 146 | 
                + <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="pMy-uJ-dNy" userLabel="Group Member">  | 
            |
| 147 | 
                + <rect key="frame" x="0.0" y="70" width="375" height="90"/>  | 
            |
| 166 | 148 | 
                <subviews>  | 
            
| 167 | 
                - <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="群成员" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="NxF-Pa-Uwm">  | 
            |
| 168 | 
                - <rect key="frame" x="12" y="12.5" width="49" height="20"/>  | 
            |
| 169 | 
                - <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>  | 
            |
| 170 | 
                - <fontDescription key="fontDescription" type="system" pointSize="16"/>  | 
            |
| 171 | 
                - <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>  | 
            |
| 172 | 
                - <nil key="highlightedColor"/>  | 
            |
| 173 | 
                - </label>  | 
            |
| 174 | 
                - <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="10人" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="AxF-rT-r4a">  | 
            |
| 175 | 
                - <rect key="frame" x="295" y="12.5" width="34" height="20"/>  | 
            |
| 176 | 
                - <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>  | 
            |
| 177 | 
                - <fontDescription key="fontDescription" type="system" pointSize="16"/>  | 
            |
| 178 | 
                - <color key="textColor" red="0.59999999999999998" green="0.59999999999999998" blue="0.59999999999999998" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>  | 
            |
| 179 | 
                - <nil key="highlightedColor"/>  | 
            |
| 180 | 
                - </label>  | 
            |
| 181 | 
                - <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="列表箭头" translatesAutoresizingMaskIntoConstraints="NO" id="deA-EV-s1P">  | 
            |
| 182 | 
                - <rect key="frame" x="339" y="4.5" width="24" height="36"/>  | 
            |
| 183 | 
                - </imageView>  | 
            |
| 149 | 
                + <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="wyR-pX-r7o">  | 
            |
| 150 | 
                + <rect key="frame" x="0.0" y="0.0" width="375" height="45"/>  | 
            |
| 151 | 
                + <subviews>  | 
            |
| 152 | 
                + <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="群成员" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="NxF-Pa-Uwm">  | 
            |
| 153 | 
                + <rect key="frame" x="12" y="12.5" width="49" height="20"/>  | 
            |
| 154 | 
                + <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>  | 
            |
| 155 | 
                + <fontDescription key="fontDescription" type="system" pointSize="16"/>  | 
            |
| 156 | 
                + <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>  | 
            |
| 157 | 
                + <nil key="highlightedColor"/>  | 
            |
| 158 | 
                + </label>  | 
            |
| 159 | 
                + <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="10人" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="AxF-rT-r4a">  | 
            |
| 160 | 
                + <rect key="frame" x="299" y="12.5" width="34" height="20"/>  | 
            |
| 161 | 
                + <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>  | 
            |
| 162 | 
                + <fontDescription key="fontDescription" type="system" pointSize="16"/>  | 
            |
| 163 | 
                + <color key="textColor" red="0.59999999999999998" green="0.59999999999999998" blue="0.59999999999999998" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>  | 
            |
| 164 | 
                + <nil key="highlightedColor"/>  | 
            |
| 165 | 
                + </label>  | 
            |
| 166 | 
                + <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="list-arrow" translatesAutoresizingMaskIntoConstraints="NO" id="deA-EV-s1P">  | 
            |
| 167 | 
                + <rect key="frame" x="339" y="4.5" width="24" height="36"/>  | 
            |
| 168 | 
                + </imageView>  | 
            |
| 169 | 
                + </subviews>  | 
            |
| 170 | 
                + <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>  | 
            |
| 171 | 
                + <constraints>  | 
            |
| 172 | 
                + <constraint firstAttribute="trailing" secondItem="deA-EV-s1P" secondAttribute="trailing" constant="12" id="99G-fm-NjO"/>  | 
            |
| 173 | 
                + <constraint firstItem="deA-EV-s1P" firstAttribute="leading" secondItem="AxF-rT-r4a" secondAttribute="trailing" constant="6" id="NoO-0x-719"/>  | 
            |
| 174 | 
                + <constraint firstAttribute="height" constant="45" id="OmQ-ue-3uc"/>  | 
            |
| 175 | 
                + <constraint firstItem="NxF-Pa-Uwm" firstAttribute="leading" secondItem="wyR-pX-r7o" secondAttribute="leading" constant="12" id="RxE-Ec-vzI"/>  | 
            |
| 176 | 
                + <constraint firstItem="NxF-Pa-Uwm" firstAttribute="centerY" secondItem="wyR-pX-r7o" secondAttribute="centerY" id="jRi-u6-4du"/>  | 
            |
| 177 | 
                + <constraint firstItem="deA-EV-s1P" firstAttribute="centerY" secondItem="wyR-pX-r7o" secondAttribute="centerY" id="lcj-B2-CSF"/>  | 
            |
| 178 | 
                + <constraint firstItem="AxF-rT-r4a" firstAttribute="centerY" secondItem="wyR-pX-r7o" secondAttribute="centerY" id="s7D-rf-GV6"/>  | 
            |
| 179 | 
                + </constraints>  | 
            |
| 180 | 
                + </view>  | 
            |
| 181 | 
                + <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="PEf-pV-jyM" customClass="GroupDetailMemeberView" customModule="Paiai_iOS" customModuleProvider="target">  | 
            |
| 182 | 
                + <rect key="frame" x="0.0" y="45" width="375" height="45"/>  | 
            |
| 183 | 
                + <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>  | 
            |
| 184 | 
                + <constraints>  | 
            |
| 185 | 
                + <constraint firstAttribute="height" constant="45" id="zVY-I6-46P"/>  | 
            |
| 186 | 
                + </constraints>  | 
            |
| 187 | 
                + </view>  | 
            |
| 184 | 188 | 
                </subviews>  | 
            
| 185 | 189 | 
                <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>  | 
            
| 186 | 190 | 
                <constraints>  | 
            
| 187 | 
                - <constraint firstAttribute="trailing" secondItem="deA-EV-s1P" secondAttribute="trailing" constant="12" id="3bb-27-Gxq"/>  | 
            |
| 188 | 
                - <constraint firstItem="deA-EV-s1P" firstAttribute="leading" secondItem="AxF-rT-r4a" secondAttribute="trailing" constant="10" id="4BA-Q0-0hV"/>  | 
            |
| 189 | 
                - <constraint firstItem="NxF-Pa-Uwm" firstAttribute="centerY" secondItem="pMy-uJ-dNy" secondAttribute="centerY" id="BZS-nD-l69"/>  | 
            |
| 190 | 
                - <constraint firstItem="AxF-rT-r4a" firstAttribute="centerY" secondItem="pMy-uJ-dNy" secondAttribute="centerY" id="MbN-zG-cZO"/>  | 
            |
| 191 | 
                - <constraint firstItem="NxF-Pa-Uwm" firstAttribute="leading" secondItem="pMy-uJ-dNy" secondAttribute="leading" constant="12" id="WQ3-O6-roa"/>  | 
            |
| 192 | 
                - <constraint firstAttribute="height" constant="45" id="ksr-Ie-zrU"/>  | 
            |
| 193 | 
                - <constraint firstItem="deA-EV-s1P" firstAttribute="centerY" secondItem="pMy-uJ-dNy" secondAttribute="centerY" id="sej-I4-LMf"/>  | 
            |
| 194 | 
                - </constraints>  | 
            |
| 195 | 
                - </view>  | 
            |
| 196 | 
                - <scrollView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" ambiguous="YES" translatesAutoresizingMaskIntoConstraints="NO" id="6Ye-xx-V3F">  | 
            |
| 197 | 
                - <rect key="frame" x="0.0" y="115" width="375" height="50"/>  | 
            |
| 198 | 
                - <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>  | 
            |
| 199 | 
                - <constraints>  | 
            |
| 200 | 
                - <constraint firstAttribute="height" constant="50" id="It1-Qr-cpK"/>  | 
            |
| 191 | 
                + <constraint firstAttribute="trailing" secondItem="PEf-pV-jyM" secondAttribute="trailing" id="FQu-9X-fNW"/>  | 
            |
| 192 | 
                + <constraint firstAttribute="trailing" secondItem="wyR-pX-r7o" secondAttribute="trailing" id="Rhr-fu-vjC"/>  | 
            |
| 193 | 
                + <constraint firstItem="PEf-pV-jyM" firstAttribute="top" secondItem="wyR-pX-r7o" secondAttribute="bottom" id="T2J-6h-hMy"/>  | 
            |
| 194 | 
                + <constraint firstAttribute="height" constant="90" id="ksr-Ie-zrU"/>  | 
            |
| 195 | 
                + <constraint firstItem="wyR-pX-r7o" firstAttribute="top" secondItem="pMy-uJ-dNy" secondAttribute="top" id="sND-x0-GOF"/>  | 
            |
| 196 | 
                + <constraint firstItem="wyR-pX-r7o" firstAttribute="leading" secondItem="pMy-uJ-dNy" secondAttribute="leading" id="wJT-Tt-evG"/>  | 
            |
| 197 | 
                + <constraint firstItem="PEf-pV-jyM" firstAttribute="leading" secondItem="pMy-uJ-dNy" secondAttribute="leading" id="xfn-6R-s6e"/>  | 
            |
| 201 | 198 | 
                </constraints>  | 
            
| 202 | 
                - </scrollView>  | 
            |
| 203 | 
                - <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="ttH-tw-fbl">  | 
            |
| 204 | 
                - <rect key="frame" x="0.0" y="70" width="375" height="95"/>  | 
            |
| 205 | 199 | 
                <connections>  | 
            
| 206 | 
                - <segue destination="bLF-bf-ZTt" kind="modal" id="C0s-8v-GKU"/>  | 
            |
| 200 | 
                + <outletCollection property="gestureRecognizers" destination="PAc-yU-TO1" appends="YES" id="HrQ-Km-0rQ"/>  | 
            |
| 207 | 201 | 
                </connections>  | 
            
| 208 | 
                - </button>  | 
            |
| 209 | 
                - <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="rPs-2T-yj8">  | 
            |
| 210 | 
                - <rect key="frame" x="0.0" y="165" width="375" height="45"/>  | 
            |
| 202 | 
                + </view>  | 
            |
| 203 | 
                + <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="rPs-2T-yj8" userLabel="Group QR">  | 
            |
| 204 | 
                + <rect key="frame" x="0.0" y="160" width="375" height="45"/>  | 
            |
| 211 | 205 | 
                <subviews>  | 
            
| 212 | 206 | 
                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="群二维码" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="ZfP-6I-3jY">  | 
            
| 213 | 207 | 
                <rect key="frame" x="12" y="12.5" width="66" height="20"/>  | 
            
                @@ -216,56 +210,33 @@  | 
            ||
| 216 | 210 | 
                <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>  | 
            
| 217 | 211 | 
                <nil key="highlightedColor"/>  | 
            
| 218 | 212 | 
                </label>  | 
            
| 219 | 
                - <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="列表箭头" translatesAutoresizingMaskIntoConstraints="NO" id="Uws-7i-Qzj">  | 
            |
| 213 | 
                + <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="list-arrow" translatesAutoresizingMaskIntoConstraints="NO" id="Uws-7i-Qzj">  | 
            |
| 220 | 214 | 
                <rect key="frame" x="339" y="4.5" width="24" height="36"/>  | 
            
| 221 | 215 | 
                </imageView>  | 
            
| 222 | 
                - <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="二维码" translatesAutoresizingMaskIntoConstraints="NO" id="ZNi-wI-pOY">  | 
            |
| 223 | 
                - <rect key="frame" x="249" y="-17.5" width="80" height="80"/>  | 
            |
| 224 | 
                - </imageView>  | 
            |
| 225 | 
                - <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="8lP-Cq-74A">  | 
            |
| 226 | 
                - <rect key="frame" x="0.0" y="0.0" width="375" height="45"/>  | 
            |
| 227 | 
                - <connections>  | 
            |
| 228 | 
                - <action selector="showEWM" destination="s9X-RR-Rat" eventType="touchUpInside" id="GIw-VW-HQt"/>  | 
            |
| 229 | 
                - </connections>  | 
            |
| 230 | 
                - </button>  | 
            |
| 231 | 
                - <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="48Y-jJ-6H8">  | 
            |
| 232 | 
                - <rect key="frame" x="0.0" y="44.5" width="375" height="0.5"/>  | 
            |
| 233 | 
                - <color key="backgroundColor" red="0.90588235289999997" green="0.90588235289999997" blue="0.90588235289999997" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>  | 
            |
| 216 | 
                + <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="list-QR" translatesAutoresizingMaskIntoConstraints="NO" id="ZNi-wI-pOY">  | 
            |
| 217 | 
                + <rect key="frame" x="305" y="10.5" width="24" height="24"/>  | 
            |
| 234 | 218 | 
                <constraints>  | 
            
| 235 | 
                - <constraint firstAttribute="height" constant="0.5" id="JC8-gM-JvE"/>  | 
            |
| 219 | 
                + <constraint firstAttribute="width" constant="24" id="DzA-gm-u2E"/>  | 
            |
| 220 | 
                + <constraint firstAttribute="height" constant="24" id="kJ3-8V-wGS"/>  | 
            |
| 236 | 221 | 
                </constraints>  | 
            
| 237 | 
                - </view>  | 
            |
| 238 | 
                - <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="rZZ-0X-2OD">  | 
            |
| 239 | 
                - <rect key="frame" x="0.0" y="0.0" width="375" height="0.5"/>  | 
            |
| 240 | 
                - <color key="backgroundColor" red="0.90588235289999997" green="0.90588235289999997" blue="0.90588235289999997" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>  | 
            |
| 241 | 
                - <constraints>  | 
            |
| 242 | 
                - <constraint firstAttribute="height" constant="0.5" id="4j1-Xu-jW0"/>  | 
            |
| 243 | 
                - </constraints>  | 
            |
| 244 | 
                - </view>  | 
            |
| 222 | 
                + </imageView>  | 
            |
| 245 | 223 | 
                </subviews>  | 
            
| 246 | 224 | 
                <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>  | 
            
| 247 | 225 | 
                <constraints>  | 
            
| 248 | 
                - <constraint firstAttribute="trailing" secondItem="rZZ-0X-2OD" secondAttribute="trailing" id="1dW-hC-FDy"/>  | 
            |
| 249 | 226 | 
                <constraint firstItem="Uws-7i-Qzj" firstAttribute="centerY" secondItem="rPs-2T-yj8" secondAttribute="centerY" id="2wQ-j8-t3z"/>  | 
            
| 250 | 227 | 
                <constraint firstAttribute="trailing" secondItem="Uws-7i-Qzj" secondAttribute="trailing" constant="12" id="7qb-cu-8iE"/>  | 
            
| 251 | 228 | 
                <constraint firstItem="ZfP-6I-3jY" firstAttribute="leading" secondItem="rPs-2T-yj8" secondAttribute="leading" constant="12" id="9xA-HF-Mlj"/>  | 
            
| 252 | 229 | 
                <constraint firstItem="ZfP-6I-3jY" firstAttribute="centerY" secondItem="rPs-2T-yj8" secondAttribute="centerY" id="GAH-Ls-Ixp"/>  | 
            
| 253 | 
                - <constraint firstItem="48Y-jJ-6H8" firstAttribute="leading" secondItem="rPs-2T-yj8" secondAttribute="leading" id="JIv-0e-gHj"/>  | 
            |
| 254 | 230 | 
                <constraint firstItem="ZNi-wI-pOY" firstAttribute="centerY" secondItem="rPs-2T-yj8" secondAttribute="centerY" id="Mst-vH-6Op"/>  | 
            
| 255 | 
                - <constraint firstItem="8lP-Cq-74A" firstAttribute="leading" secondItem="rPs-2T-yj8" secondAttribute="leading" id="NMw-0N-fZx"/>  | 
            |
| 256 | 
                - <constraint firstAttribute="trailing" secondItem="48Y-jJ-6H8" secondAttribute="trailing" id="VtK-02-UJa"/>  | 
            |
| 257 | 
                - <constraint firstItem="rZZ-0X-2OD" firstAttribute="top" secondItem="rPs-2T-yj8" secondAttribute="top" id="Z6z-RI-FFz"/>  | 
            |
| 258 | 
                - <constraint firstItem="rZZ-0X-2OD" firstAttribute="leading" secondItem="rPs-2T-yj8" secondAttribute="leading" id="d4k-V8-dK8"/>  | 
            |
| 259 | 231 | 
                <constraint firstItem="Uws-7i-Qzj" firstAttribute="leading" secondItem="ZNi-wI-pOY" secondAttribute="trailing" constant="10" id="eQT-7f-sku"/>  | 
            
| 260 | 
                - <constraint firstAttribute="bottom" secondItem="48Y-jJ-6H8" secondAttribute="bottom" id="f3e-9q-qtH"/>  | 
            |
| 261 | 
                - <constraint firstAttribute="trailing" secondItem="8lP-Cq-74A" secondAttribute="trailing" id="l98-kH-PHH"/>  | 
            |
| 262 | 
                - <constraint firstItem="8lP-Cq-74A" firstAttribute="top" secondItem="rPs-2T-yj8" secondAttribute="top" id="wCy-B2-xGE"/>  | 
            |
| 263 | 
                - <constraint firstAttribute="bottom" secondItem="8lP-Cq-74A" secondAttribute="bottom" id="wkR-RU-Ksc"/>  | 
            |
| 264 | 232 | 
                <constraint firstAttribute="height" constant="45" id="ypH-Mg-3iM"/>  | 
            
| 265 | 233 | 
                </constraints>  | 
            
| 234 | 
                + <connections>  | 
            |
| 235 | 
                + <outletCollection property="gestureRecognizers" destination="CLv-er-MwX" appends="YES" id="6Fw-lQ-Aqq"/>  | 
            |
| 236 | 
                + </connections>  | 
            |
| 266 | 237 | 
                </view>  | 
            
| 267 | 
                - <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Pb3-YX-nuZ">  | 
            |
| 268 | 
                - <rect key="frame" x="0.0" y="210" width="375" height="45"/>  | 
            |
| 238 | 
                + <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Pb3-YX-nuZ" userLabel="Group Lock">  | 
            |
| 239 | 
                + <rect key="frame" x="0.0" y="205" width="375" height="45"/>  | 
            |
| 269 | 240 | 
                <subviews>  | 
            
| 270 | 241 | 
                <switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="1000" verticalHuggingPriority="750" horizontalCompressionResistancePriority="1000" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="t9Z-kG-PPs">  | 
            
| 271 | 242 | 
                <rect key="frame" x="314" y="7" width="51" height="31"/>  | 
            
                @@ -291,6 +262,7 @@  | 
            ||
| 291 | 262 | 
                </subviews>  | 
            
| 292 | 263 | 
                <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>  | 
            
| 293 | 264 | 
                <constraints>  | 
            
| 265 | 
                + <constraint firstAttribute="trailing" secondItem="t9Z-kG-PPs" secondAttribute="trailing" constant="12" id="KkU-tC-Egu"/>  | 
            |
| 294 | 266 | 
                <constraint firstAttribute="height" constant="45" id="SJk-Ib-saK"/>  | 
            
| 295 | 267 | 
                <constraint firstItem="t9Z-kG-PPs" firstAttribute="leading" secondItem="niR-rQ-aFl" secondAttribute="trailing" constant="16" id="fz2-LG-fUc"/>  | 
            
| 296 | 268 | 
                <constraint firstItem="pGa-DR-SDU" firstAttribute="centerY" secondItem="Pb3-YX-nuZ" secondAttribute="centerY" id="g0e-A6-o5n"/>  | 
            
                @@ -303,56 +275,59 @@  | 
            ||
| 303 | 275 | 
                </subviews>  | 
            
| 304 | 276 | 
                <color key="backgroundColor" red="0.94117647058823528" green="0.94117647058823528" blue="0.94117647058823528" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>  | 
            
| 305 | 277 | 
                <constraints>  | 
            
| 306 | 
                - <constraint firstItem="ttH-tw-fbl" firstAttribute="top" secondItem="fpL-PF-0xo" secondAttribute="bottom" id="6cp-ka-r88"/>  | 
            |
| 307 | 
                - <constraint firstItem="6Ye-xx-V3F" firstAttribute="top" secondItem="pMy-uJ-dNy" secondAttribute="bottom" id="C1f-d3-HD9"/>  | 
            |
| 308 | 
                - <constraint firstItem="pMy-uJ-dNy" firstAttribute="leading" secondItem="OXa-NJ-XOO" secondAttribute="leading" id="DJT-ec-BYi"/>  | 
            |
| 309 | 
                - <constraint firstAttribute="trailing" secondItem="Pb3-YX-nuZ" secondAttribute="trailing" id="GHr-gH-44j"/>  | 
            |
| 310 | 
                - <constraint firstAttribute="trailing" secondItem="rPs-2T-yj8" secondAttribute="trailing" id="SBF-Gf-sea"/>  | 
            |
| 311 | 
                - <constraint firstItem="6Ye-xx-V3F" firstAttribute="leading" secondItem="OXa-NJ-XOO" secondAttribute="leading" id="Vp9-OK-KTg"/>  | 
            |
| 312 | 
                - <constraint firstAttribute="trailing" secondItem="6Ye-xx-V3F" secondAttribute="trailing" id="XOF-8e-oMx"/>  | 
            |
| 313 | 
                - <constraint firstAttribute="trailing" secondItem="fpL-PF-0xo" secondAttribute="trailing" id="dKZ-bN-aud"/>  | 
            |
| 314 | 
                - <constraint firstItem="fpL-PF-0xo" firstAttribute="leading" secondItem="OXa-NJ-XOO" secondAttribute="leading" id="dvc-Qp-fCK"/>  | 
            |
| 315 | 
                - <constraint firstItem="rPs-2T-yj8" firstAttribute="top" secondItem="ttH-tw-fbl" secondAttribute="bottom" id="dzI-1e-y1G"/>  | 
            |
| 316 | 
                - <constraint firstItem="rPs-2T-yj8" firstAttribute="leading" secondItem="OXa-NJ-XOO" secondAttribute="leading" id="exJ-yM-58B"/>  | 
            |
| 317 | 
                - <constraint firstItem="ttH-tw-fbl" firstAttribute="leading" secondItem="OXa-NJ-XOO" secondAttribute="leading" id="fiH-X6-HUW"/>  | 
            |
| 278 | 
                + <constraint firstItem="pMy-uJ-dNy" firstAttribute="leading" secondItem="cIo-kp-fSE" secondAttribute="leading" id="DJT-ec-BYi"/>  | 
            |
| 279 | 
                + <constraint firstItem="cIo-kp-fSE" firstAttribute="trailing" secondItem="Pb3-YX-nuZ" secondAttribute="trailing" id="GHr-gH-44j"/>  | 
            |
| 280 | 
                + <constraint firstItem="rPs-2T-yj8" firstAttribute="top" secondItem="pMy-uJ-dNy" secondAttribute="bottom" id="PC0-el-XOL"/>  | 
            |
| 281 | 
                + <constraint firstItem="cIo-kp-fSE" firstAttribute="trailing" secondItem="rPs-2T-yj8" secondAttribute="trailing" id="SBF-Gf-sea"/>  | 
            |
| 282 | 
                + <constraint firstItem="cIo-kp-fSE" firstAttribute="trailing" secondItem="fpL-PF-0xo" secondAttribute="trailing" id="dKZ-bN-aud"/>  | 
            |
| 283 | 
                + <constraint firstItem="fpL-PF-0xo" firstAttribute="leading" secondItem="cIo-kp-fSE" secondAttribute="leading" id="dvc-Qp-fCK"/>  | 
            |
| 284 | 
                + <constraint firstItem="rPs-2T-yj8" firstAttribute="leading" secondItem="cIo-kp-fSE" secondAttribute="leading" id="exJ-yM-58B"/>  | 
            |
| 318 | 285 | 
                <constraint firstItem="pMy-uJ-dNy" firstAttribute="top" secondItem="fpL-PF-0xo" secondAttribute="bottom" id="iBX-Qu-4Rh"/>  | 
            
| 319 | 
                - <constraint firstItem="t9Z-kG-PPs" firstAttribute="trailing" secondItem="Uws-7i-Qzj" secondAttribute="trailing" id="ir1-U9-9vc"/>  | 
            |
| 320 | 
                - <constraint firstItem="Pb3-YX-nuZ" firstAttribute="leading" secondItem="OXa-NJ-XOO" secondAttribute="leading" id="lm3-hT-PcR"/>  | 
            |
| 321 | 
                - <constraint firstAttribute="trailing" secondItem="pMy-uJ-dNy" secondAttribute="trailing" id="mOe-DU-Rdn"/>  | 
            |
| 286 | 
                + <constraint firstItem="Pb3-YX-nuZ" firstAttribute="leading" secondItem="cIo-kp-fSE" secondAttribute="leading" id="lm3-hT-PcR"/>  | 
            |
| 287 | 
                + <constraint firstItem="cIo-kp-fSE" firstAttribute="trailing" secondItem="pMy-uJ-dNy" secondAttribute="trailing" id="mOe-DU-Rdn"/>  | 
            |
| 322 | 288 | 
                <constraint firstItem="Pb3-YX-nuZ" firstAttribute="top" secondItem="rPs-2T-yj8" secondAttribute="bottom" id="ow5-8x-3xA"/>  | 
            
| 323 | 
                - <constraint firstItem="rPs-2T-yj8" firstAttribute="top" secondItem="6Ye-xx-V3F" secondAttribute="bottom" id="vGu-Nc-0B8"/>  | 
            |
| 324 | 
                - <constraint firstItem="fpL-PF-0xo" firstAttribute="top" secondItem="w38-w0-jLd" secondAttribute="bottom" constant="5" id="wQP-uP-4dl"/>  | 
            |
| 325 | 
                - <constraint firstAttribute="trailing" secondItem="ttH-tw-fbl" secondAttribute="trailing" id="ymt-0n-er5"/>  | 
            |
| 289 | 
                + <constraint firstItem="fpL-PF-0xo" firstAttribute="top" secondItem="cIo-kp-fSE" secondAttribute="top" constant="5" id="wQP-uP-4dl"/>  | 
            |
| 326 | 290 | 
                </constraints>  | 
            
| 291 | 
                + <viewLayoutGuide key="safeArea" id="cIo-kp-fSE"/>  | 
            |
| 327 | 292 | 
                </view>  | 
            
| 328 | 293 | 
                <navigationItem key="navigationItem" id="Cjc-V8-n6M"/>  | 
            
| 329 | 294 | 
                <connections>  | 
            
| 330 | 295 | 
                <outlet property="groupLockSwitch" destination="t9Z-kG-PPs" id="mJz-yT-bcT"/>  | 
            
| 331 | 296 | 
                <outlet property="groupLockTip" destination="niR-rQ-aFl" id="AX6-6k-zux"/>  | 
            
| 332 | 
                - <outlet property="groupNameLabel" destination="1X6-D5-hkj" id="rM6-pN-lg1"/>  | 
            |
| 333 | 
                - <outlet property="groupUserCountLabel" destination="AxF-rT-r4a" id="eOC-vz-TTc"/>  | 
            |
| 334 | 
                - <outlet property="groupUserHeaderScrollView" destination="6Ye-xx-V3F" id="VvQ-Bd-bZq"/>  | 
            |
| 335 | 
                - <outlet property="scrollViewConstraint" destination="It1-Qr-cpK" id="ume-bG-RSv"/>  | 
            |
| 297 | 
                + <outlet property="groupMemberCountLabel" destination="AxF-rT-r4a" id="eOC-vz-TTc"/>  | 
            |
| 298 | 
                + <outlet property="groupMemeberView" destination="PEf-pV-jyM" id="Cqs-Fq-QzC"/>  | 
            |
| 299 | 
                + <outlet property="groupNameLabel" destination="1X6-D5-hkj" id="neB-7y-IOQ"/>  | 
            |
| 336 | 300 | 
                </connections>  | 
            
| 337 | 301 | 
                </viewController>  | 
            
| 338 | 302 | 
                <placeholder placeholderIdentifier="IBFirstResponder" id="3Gk-LZ-t7S" sceneMemberID="firstResponder"/>  | 
            
| 303 | 
                + <tapGestureRecognizer id="QhO-Be-7C1" userLabel="GroupNameGesture">  | 
            |
| 304 | 
                + <connections>  | 
            |
| 305 | 
                + <action selector="navigationToGroupNameModification:" destination="s9X-RR-Rat" id="R9K-8v-b14"/>  | 
            |
| 306 | 
                + </connections>  | 
            |
| 307 | 
                + </tapGestureRecognizer>  | 
            |
| 308 | 
                + <tapGestureRecognizer id="PAc-yU-TO1" userLabel="GroupMemeberGesture">  | 
            |
| 309 | 
                + <connections>  | 
            |
| 310 | 
                + <action selector="navigationToGroupMember:" destination="s9X-RR-Rat" id="V81-eM-vdl"/>  | 
            |
| 311 | 
                + </connections>  | 
            |
| 312 | 
                + </tapGestureRecognizer>  | 
            |
| 313 | 
                + <tapGestureRecognizer id="CLv-er-MwX" userLabel="GroupQRGesture">  | 
            |
| 314 | 
                + <connections>  | 
            |
| 315 | 
                + <action selector="presentGroupQR:" destination="s9X-RR-Rat" id="RHF-fz-Emo"/>  | 
            |
| 316 | 
                + </connections>  | 
            |
| 317 | 
                + </tapGestureRecognizer>  | 
            |
| 339 | 318 | 
                </objects>  | 
            
| 340 | 319 | 
                <point key="canvasLocation" x="-983.20000000000005" y="926.08695652173924"/>  | 
            
| 341 | 320 | 
                </scene>  | 
            
| 342 | 
                - <!--ChangeGroupNameController-->  | 
            |
| 321 | 
                + <!--GroupNameModificationViewController-->  | 
            |
| 343 | 322 | 
                <scene sceneID="LCo-hF-TXa">  | 
            
| 344 | 323 | 
                <objects>  | 
            
| 345 | 
                - <viewController storyboardIdentifier="ChangeGroupNameController" id="xy6-fJ-25c" userLabel="ChangeGroupNameController" customClass="ChangeGroupNameController" customModule="PaiAi" sceneMemberID="viewController">  | 
            |
| 346 | 
                - <layoutGuides>  | 
            |
| 347 | 
                - <viewControllerLayoutGuide type="top" id="js2-YR-fZ8"/>  | 
            |
| 348 | 
                - <viewControllerLayoutGuide type="bottom" id="UR6-vz-0Cc"/>  | 
            |
| 349 | 
                - </layoutGuides>  | 
            |
| 324 | 
                + <viewController storyboardIdentifier="GroupNameModificationViewController" id="xy6-fJ-25c" userLabel="GroupNameModificationViewController" customClass="GroupNameModificationViewController" customModule="Paiai_iOS" customModuleProvider="target" sceneMemberID="viewController">  | 
            |
| 350 | 325 | 
                <view key="view" contentMode="scaleToFill" id="k0W-jb-XQ1">  | 
            
| 351 | 326 | 
                <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>  | 
            
| 352 | 327 | 
                <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>  | 
            
| 353 | 328 | 
                <subviews>  | 
            
| 354 | 329 | 
                <textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="群名称" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="8A1-xH-nsg">  | 
            
| 355 | 
                - <rect key="frame" x="0.0" y="64" width="375" height="44"/>  | 
            |
| 330 | 
                + <rect key="frame" x="0.0" y="20" width="375" height="44"/>  | 
            |
| 356 | 331 | 
                <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>  | 
            
| 357 | 332 | 
                <constraints>  | 
            
| 358 | 333 | 
                <constraint firstAttribute="height" constant="44" id="K1B-yr-x1W"/>  | 
            
                @@ -361,12 +336,12 @@  | 
            ||
| 361 | 336 | 
                <textInputTraits key="textInputTraits"/>  | 
            
| 362 | 337 | 
                </textField>  | 
            
| 363 | 338 | 
                <button opaque="NO" contentMode="scaleToFill" enabled="NO" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="6ys-SB-QLv">  | 
            
| 364 | 
                - <rect key="frame" x="0.0" y="138" width="375" height="48"/>  | 
            |
| 339 | 
                + <rect key="frame" x="0.0" y="94" width="375" height="48"/>  | 
            |
| 365 | 340 | 
                <constraints>  | 
            
| 366 | 341 | 
                <constraint firstAttribute="height" constant="48" id="VPL-IJ-M2Y"/>  | 
            
| 367 | 342 | 
                </constraints>  | 
            
| 368 | 343 | 
                <fontDescription key="fontDescription" type="system" pointSize="18"/>  | 
            
| 369 | 
                - <state key="normal" title="保存" backgroundImage="标题栏 copy 2">  | 
            |
| 344 | 
                + <state key="normal" title="保存" backgroundImage="navigation-background">  | 
            |
| 370 | 345 | 
                <color key="titleColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>  | 
            
| 371 | 346 | 
                </state>  | 
            
| 372 | 347 | 
                <connections>  | 
            
                @@ -378,12 +353,13 @@  | 
            ||
| 378 | 353 | 
                <gestureRecognizers/>  | 
            
| 379 | 354 | 
                <constraints>  | 
            
| 380 | 355 | 
                <constraint firstItem="6ys-SB-QLv" firstAttribute="top" secondItem="8A1-xH-nsg" secondAttribute="bottom" constant="30" id="4qN-11-vnF"/>  | 
            
| 381 | 
                - <constraint firstItem="6ys-SB-QLv" firstAttribute="leading" secondItem="k0W-jb-XQ1" secondAttribute="leading" id="Fen-r1-swQ"/>  | 
            |
| 382 | 
                - <constraint firstAttribute="trailing" secondItem="6ys-SB-QLv" secondAttribute="trailing" id="KeF-22-9xs"/>  | 
            |
| 383 | 
                - <constraint firstItem="8A1-xH-nsg" firstAttribute="top" secondItem="js2-YR-fZ8" secondAttribute="bottom" id="O3J-RE-wko"/>  | 
            |
| 384 | 
                - <constraint firstItem="8A1-xH-nsg" firstAttribute="leading" secondItem="k0W-jb-XQ1" secondAttribute="leading" id="a8E-Fz-s5Z"/>  | 
            |
| 385 | 
                - <constraint firstAttribute="trailing" secondItem="8A1-xH-nsg" secondAttribute="trailing" id="cAq-3V-p2y"/>  | 
            |
| 356 | 
                + <constraint firstItem="6ys-SB-QLv" firstAttribute="leading" secondItem="Xk6-cx-bQU" secondAttribute="leading" id="Fen-r1-swQ"/>  | 
            |
| 357 | 
                + <constraint firstItem="Xk6-cx-bQU" firstAttribute="trailing" secondItem="6ys-SB-QLv" secondAttribute="trailing" id="KeF-22-9xs"/>  | 
            |
| 358 | 
                + <constraint firstItem="8A1-xH-nsg" firstAttribute="top" secondItem="Xk6-cx-bQU" secondAttribute="top" id="O3J-RE-wko"/>  | 
            |
| 359 | 
                + <constraint firstItem="8A1-xH-nsg" firstAttribute="leading" secondItem="Xk6-cx-bQU" secondAttribute="leading" id="a8E-Fz-s5Z"/>  | 
            |
| 360 | 
                + <constraint firstItem="Xk6-cx-bQU" firstAttribute="trailing" secondItem="8A1-xH-nsg" secondAttribute="trailing" id="cAq-3V-p2y"/>  | 
            |
| 386 | 361 | 
                </constraints>  | 
            
| 362 | 
                + <viewLayoutGuide key="safeArea" id="Xk6-cx-bQU"/>  | 
            |
| 387 | 363 | 
                <connections>  | 
            
| 388 | 364 | 
                <outletCollection property="gestureRecognizers" destination="TeB-xY-v1V" appends="YES" id="o89-cE-p8S"/>  | 
            
| 389 | 365 | 
                </connections>  | 
            
                @@ -403,24 +379,20 @@  | 
            ||
| 403 | 379 | 
                </objects>  | 
            
| 404 | 380 | 
                <point key="canvasLocation" x="665.60000000000002" y="277.06146926536735"/>  | 
            
| 405 | 381 | 
                </scene>  | 
            
| 406 | 
                - <!--GroupUserController-->  | 
            |
| 382 | 
                + <!--GroupMemberViewController-->  | 
            |
| 407 | 383 | 
                <scene sceneID="LEa-gB-9eo">  | 
            
| 408 | 384 | 
                <objects>  | 
            
| 409 | 
                - <viewController storyboardIdentifier="GroupUserController" id="DUe-lx-JN1" userLabel="GroupUserController" customClass="GroupUserController" customModule="PaiAi" sceneMemberID="viewController">  | 
            |
| 410 | 
                - <layoutGuides>  | 
            |
| 411 | 
                - <viewControllerLayoutGuide type="top" id="akD-at-rrg"/>  | 
            |
| 412 | 
                - <viewControllerLayoutGuide type="bottom" id="Yii-Z2-rvQ"/>  | 
            |
| 413 | 
                - </layoutGuides>  | 
            |
| 385 | 
                + <viewController storyboardIdentifier="GroupMemberViewController" id="DUe-lx-JN1" userLabel="GroupMemberViewController" customClass="GroupMemberViewController" customModule="Paiai_iOS" customModuleProvider="target" sceneMemberID="viewController">  | 
            |
| 414 | 386 | 
                <view key="view" contentMode="scaleToFill" id="wjV-Cy-YkZ">  | 
            
| 415 | 387 | 
                <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>  | 
            
| 416 | 388 | 
                <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>  | 
            
| 417 | 389 | 
                <subviews>  | 
            
| 418 | 390 | 
                <tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" rowHeight="44" sectionHeaderHeight="28" sectionFooterHeight="28" translatesAutoresizingMaskIntoConstraints="NO" id="cas-Ep-jsP">  | 
            
| 419 | 
                - <rect key="frame" x="0.0" y="6" width="375" height="661"/>  | 
            |
| 391 | 
                + <rect key="frame" x="0.0" y="20" width="375" height="647"/>  | 
            |
| 420 | 392 | 
                <color key="backgroundColor" red="0.94901960780000005" green="0.94901960780000005" blue="0.94901960780000005" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>  | 
            
| 421 | 393 | 
                <color key="separatorColor" red="0.94117647058823528" green="0.94117647058823528" blue="0.94117647058823528" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>  | 
            
| 422 | 394 | 
                <prototypes>  | 
            
| 423 | 
                - <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" reuseIdentifier="MemberCell" rowHeight="50" id="DJ1-Ig-ZYH" customClass="MemberCell" customModule="Paiai_iOS" customModuleProvider="target">  | 
            |
| 395 | 
                + <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" reuseIdentifier="groupMemberCell" rowHeight="50" id="DJ1-Ig-ZYH" customClass="GroupMemberCell" customModule="Paiai_iOS" customModuleProvider="target">  | 
            |
| 424 | 396 | 
                <rect key="frame" x="0.0" y="28" width="375" height="50"/>  | 
            
| 425 | 397 | 
                <autoresizingMask key="autoresizingMask"/>  | 
            
| 426 | 398 | 
                <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="DJ1-Ig-ZYH" id="IJX-qw-roh">  | 
            
                @@ -500,11 +472,12 @@  | 
            ||
| 500 | 472 | 
                </subviews>  | 
            
| 501 | 473 | 
                <color key="backgroundColor" red="0.94117647058823528" green="0.94117647058823528" blue="0.94117647058823528" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>  | 
            
| 502 | 474 | 
                <constraints>  | 
            
| 503 | 
                - <constraint firstItem="Yii-Z2-rvQ" firstAttribute="top" secondItem="cas-Ep-jsP" secondAttribute="bottom" id="A2j-Na-7en"/>  | 
            |
| 504 | 
                - <constraint firstItem="cas-Ep-jsP" firstAttribute="leading" secondItem="wjV-Cy-YkZ" secondAttribute="leading" id="NW3-AC-Ax4"/>  | 
            |
| 505 | 
                - <constraint firstItem="cas-Ep-jsP" firstAttribute="top" secondItem="akD-at-rrg" secondAttribute="bottom" constant="-64" id="NvE-Ok-Rur"/>  | 
            |
| 506 | 
                - <constraint firstAttribute="trailing" secondItem="cas-Ep-jsP" secondAttribute="trailing" id="PPv-Ze-mtL"/>  | 
            |
| 475 | 
                + <constraint firstItem="D3F-7B-V4M" firstAttribute="bottom" secondItem="cas-Ep-jsP" secondAttribute="bottom" id="A2j-Na-7en"/>  | 
            |
| 476 | 
                + <constraint firstItem="cas-Ep-jsP" firstAttribute="leading" secondItem="D3F-7B-V4M" secondAttribute="leading" id="NW3-AC-Ax4"/>  | 
            |
| 477 | 
                + <constraint firstItem="cas-Ep-jsP" firstAttribute="top" secondItem="D3F-7B-V4M" secondAttribute="top" id="NvE-Ok-Rur"/>  | 
            |
| 478 | 
                + <constraint firstItem="D3F-7B-V4M" firstAttribute="trailing" secondItem="cas-Ep-jsP" secondAttribute="trailing" id="PPv-Ze-mtL"/>  | 
            |
| 507 | 479 | 
                </constraints>  | 
            
| 480 | 
                + <viewLayoutGuide key="safeArea" id="D3F-7B-V4M"/>  | 
            |
| 508 | 481 | 
                </view>  | 
            
| 509 | 482 | 
                <navigationItem key="navigationItem" id="7KI-2g-oIA"/>  | 
            
| 510 | 483 | 
                <connections>  | 
            
                @@ -515,48 +488,12 @@  | 
            ||
| 515 | 488 | 
                </objects>  | 
            
| 516 | 489 | 
                <point key="canvasLocation" x="665.60000000000002" y="1461.7691154422789"/>  | 
            
| 517 | 490 | 
                </scene>  | 
            
| 518 | 
                - <!--Navigation Controller-->  | 
            |
| 519 | 
                - <scene sceneID="ov2-RO-i1Z">  | 
            |
| 520 | 
                - <objects>  | 
            |
| 521 | 
                - <navigationController automaticallyAdjustsScrollViewInsets="NO" id="ahh-gm-C2t" sceneMemberID="viewController">  | 
            |
| 522 | 
                - <toolbarItems/>  | 
            |
| 523 | 
                - <navigationBar key="navigationBar" contentMode="scaleToFill" id="6Xa-cD-JBm">  | 
            |
| 524 | 
                - <rect key="frame" x="0.0" y="20" width="375" height="44"/>  | 
            |
| 525 | 
                - <autoresizingMask key="autoresizingMask"/>  | 
            |
| 526 | 
                - </navigationBar>  | 
            |
| 527 | 
                - <nil name="viewControllers"/>  | 
            |
| 528 | 
                - <connections>  | 
            |
| 529 | 
                - <segue destination="xy6-fJ-25c" kind="relationship" relationship="rootViewController" id="cOL-rO-K5H"/>  | 
            |
| 530 | 
                - </connections>  | 
            |
| 531 | 
                - </navigationController>  | 
            |
| 532 | 
                - <placeholder placeholderIdentifier="IBFirstResponder" id="KNI-l3-BnW" userLabel="First Responder" sceneMemberID="firstResponder"/>  | 
            |
| 533 | 
                - </objects>  | 
            |
| 534 | 
                - <point key="canvasLocation" x="-228.80000000000001" y="277.06146926536735"/>  | 
            |
| 535 | 
                - </scene>  | 
            |
| 536 | 
                - <!--Navigation Controller-->  | 
            |
| 537 | 
                - <scene sceneID="5Kq-iV-cq7">  | 
            |
| 538 | 
                - <objects>  | 
            |
| 539 | 
                - <navigationController automaticallyAdjustsScrollViewInsets="NO" id="bLF-bf-ZTt" sceneMemberID="viewController">  | 
            |
| 540 | 
                - <toolbarItems/>  | 
            |
| 541 | 
                - <navigationBar key="navigationBar" contentMode="scaleToFill" id="XDR-Gh-5JG">  | 
            |
| 542 | 
                - <rect key="frame" x="0.0" y="20" width="375" height="44"/>  | 
            |
| 543 | 
                - <autoresizingMask key="autoresizingMask"/>  | 
            |
| 544 | 
                - </navigationBar>  | 
            |
| 545 | 
                - <nil name="viewControllers"/>  | 
            |
| 546 | 
                - <connections>  | 
            |
| 547 | 
                - <segue destination="DUe-lx-JN1" kind="relationship" relationship="rootViewController" id="eVW-yF-vp0"/>  | 
            |
| 548 | 
                - </connections>  | 
            |
| 549 | 
                - </navigationController>  | 
            |
| 550 | 
                - <placeholder placeholderIdentifier="IBFirstResponder" id="ewD-Hk-TCe" userLabel="First Responder" sceneMemberID="firstResponder"/>  | 
            |
| 551 | 
                - </objects>  | 
            |
| 552 | 
                - <point key="canvasLocation" x="-230.40000000000001" y="1461.7691154422789"/>  | 
            |
| 553 | 
                - </scene>  | 
            |
| 554 | 491 | 
                </scenes>  | 
            
| 555 | 492 | 
                <resources>  | 
            
| 556 | 493 | 
                <image name="delete" width="66" height="66"/>  | 
            
| 557 | 
                - <image name="二维码" width="80" height="80"/>  | 
            |
| 558 | 
                - <image name="列表箭头" width="24" height="36"/>  | 
            |
| 559 | 
                - <image name="标题栏 copy 2" width="6" height="66"/>  | 
            |
| 494 | 
                + <image name="list-QR" width="36" height="36"/>  | 
            |
| 495 | 
                + <image name="list-arrow" width="24" height="36"/>  | 
            |
| 496 | 
                + <image name="navigation-background" width="12" height="132"/>  | 
            |
| 560 | 497 | 
                <image name="默认头像" width="240" height="240"/>  | 
            
| 561 | 498 | 
                </resources>  | 
            
| 562 | 499 | 
                </document>  | 
            
                @@ -6,7 +6,8 @@  | 
            ||
| 6 | 6 | 
                // Copyright © 2018 yb. All rights reserved.  | 
            
| 7 | 7 | 
                //  | 
            
| 8 | 8 | 
                 | 
            
| 9 | 
                -import Foundation  | 
            |
| 9 | 
                +import UIKit  | 
            |
| 10 | 
                +import PaiaiDataKit  | 
            |
| 10 | 11 | 
                 | 
            
| 11 | 12 | 
                 class GroupDetailCoordinator: Coordinator {
               | 
            
| 12 | 13 | 
                let navigationController: UINavigationController  | 
            
                @@ -16,7 +17,35 @@ class GroupDetailCoordinator: Coordinator {
               | 
            ||
| 16 | 17 | 
                self.groupDetailViewController = groupDetailVC  | 
            
| 17 | 18 | 
                self.navigationController = navigationController  | 
            
| 18 | 19 | 
                 | 
            
| 19 | 
                -// groupViewController.viewModel.delegate = self  | 
            |
| 20 | 
                + groupDetailViewController.viewModel.delegate = self  | 
            |
| 21 | 
                + }  | 
            |
| 22 | 
                +}  | 
            |
| 23 | 
                +  | 
            |
| 24 | 
                +extension GroupDetailCoordinator: GroupDetailViewModelDelegate {
               | 
            |
| 25 | 
                +    func navigationToRootViewController() {
               | 
            |
| 26 | 
                + navigationController.popToRootViewController(animated: true)  | 
            |
| 27 | 
                + }  | 
            |
| 28 | 
                +  | 
            |
| 29 | 
                +    func navigationToGroupMember(_ item: GroupDetailItem) {
               | 
            |
| 30 | 
                + navigationController.pushViewController(makeGroupMemberViewController(item))  | 
            |
| 31 | 
                + }  | 
            |
| 32 | 
                +  | 
            |
| 33 | 
                +    func navigationToGroupNameModification(_ item: GroupDetailItem) {
               | 
            |
| 34 | 
                + navigationController.pushViewController(makeGroupNameModificationViewController(item))  | 
            |
| 35 | 
                + }  | 
            |
| 36 | 
                +}  | 
            |
| 37 | 
                +  | 
            |
| 38 | 
                +extension GroupDetailCoordinator {
               | 
            |
| 39 | 
                +    func makeGroupMemberViewController(_ item: GroupDetailItem) -> GroupMemberViewController {
               | 
            |
| 40 | 
                + let vc = UIStoryboard.groupDetail.instantiateController(GroupMemberViewController.self)  | 
            |
| 41 | 
                + vc.viewModel = GroupMemberViewModel(item: item)  | 
            |
| 42 | 
                + return vc  | 
            |
| 43 | 
                + }  | 
            |
| 44 | 
                +  | 
            |
| 45 | 
                +    func makeGroupNameModificationViewController(_ item: GroupDetailItem) -> GroupNameModificationViewController {
               | 
            |
| 46 | 
                + let vc = UIStoryboard.groupDetail.instantiateController(GroupNameModificationViewController.self)  | 
            |
| 47 | 
                + vc.item = item  | 
            |
| 48 | 
                + return vc  | 
            |
| 20 | 49 | 
                }  | 
            
| 21 | 50 | 
                }  | 
            
| 22 | 51 | 
                 | 
            
                @@ -9,13 +9,52 @@  | 
            ||
| 9 | 9 | 
                import UIKit  | 
            
| 10 | 10 | 
                 | 
            
| 11 | 11 | 
                 class GroupDetailMemeberView: UIView {
               | 
            
| 12 | 
                -  | 
            |
| 13 | 
                - /*  | 
            |
| 14 | 
                - // Only override draw() if you perform custom drawing.  | 
            |
| 15 | 
                - // An empty implementation adversely affects performance during animation.  | 
            |
| 16 | 
                -    override func draw(_ rect: CGRect) {
               | 
            |
| 17 | 
                - // Drawing code  | 
            |
| 12 | 
                +    var avatars = [String]() {
               | 
            |
| 13 | 
                +        didSet {
               | 
            |
| 14 | 
                + constructViewHierarchy()  | 
            |
| 15 | 
                + activateConstraints()  | 
            |
| 16 | 
                + }  | 
            |
| 17 | 
                + }  | 
            |
| 18 | 
                +  | 
            |
| 19 | 
                + private var imageViews = [UIImageView]()  | 
            |
| 20 | 
                + private var visiableMembersCount = 0  | 
            |
| 21 | 
                + private var space: CGFloat = 0  | 
            |
| 22 | 
                +  | 
            |
| 23 | 
                +    override func didMoveToWindow() {
               | 
            |
| 24 | 
                + visiableMembersCount = Int((width - 6) / 46)  | 
            |
| 25 | 
                + space = (width - CGFloat(40 * visiableMembersCount)) / CGFloat(visiableMembersCount + 1)  | 
            |
| 26 | 
                + }  | 
            |
| 27 | 
                +  | 
            |
| 28 | 
                +    func constructViewHierarchy() {
               | 
            |
| 29 | 
                +        imageViews.forEach { $0.removeFromSuperview() }
               | 
            |
| 30 | 
                + imageViews.removeAll()  | 
            |
| 31 | 
                +  | 
            |
| 32 | 
                +  | 
            |
| 33 | 
                +        for avatar in avatars {
               | 
            |
| 34 | 
                + let imageView = UIImageView()  | 
            |
| 35 | 
                +  | 
            |
| 36 | 
                + imageView.cornerRadius = 5  | 
            |
| 37 | 
                + imageView.setImage(avatar, placeholder: UIImage.defaultAvatar)  | 
            |
| 38 | 
                +  | 
            |
| 39 | 
                + addSubview(imageView)  | 
            |
| 40 | 
                + imageViews.append(imageView)  | 
            |
| 41 | 
                + }  | 
            |
| 42 | 
                + }  | 
            |
| 43 | 
                +  | 
            |
| 44 | 
                +    func activateConstraints() {
               | 
            |
| 45 | 
                + var last: UIImageView?  | 
            |
| 46 | 
                +        for imageView in imageViews {
               | 
            |
| 47 | 
                + imageView.translatesAutoresizingMaskIntoConstraints = false  | 
            |
| 48 | 
                +  | 
            |
| 49 | 
                + NSLayoutConstraint.activate([  | 
            |
| 50 | 
                + imageView.widthAnchor.constraint(equalToConstant: 40),  | 
            |
| 51 | 
                + imageView.heightAnchor.constraint(equalToConstant: 40),  | 
            |
| 52 | 
                + imageView.centerYAnchor.constraint(equalTo: centerYAnchor),  | 
            |
| 53 | 
                + imageView.leadingAnchor.constraint(equalTo: last?.trailingAnchor ?? leadingAnchor, constant: space)  | 
            |
| 54 | 
                + ])  | 
            |
| 55 | 
                +  | 
            |
| 56 | 
                + last = imageView  | 
            |
| 57 | 
                + }  | 
            |
| 18 | 58 | 
                }  | 
            
| 19 | 
                - */  | 
            |
| 20 | 
                -  | 
            |
| 21 | 59 | 
                }  | 
            
| 60 | 
                +  | 
            
                @@ -14,120 +14,104 @@ import PaiaiDataKit  | 
            ||
| 14 | 14 | 
                 | 
            
| 15 | 15 | 
                 final class GroupDetailViewController: UIViewController {
               | 
            
| 16 | 16 | 
                 | 
            
| 17 | 
                + @IBOutlet weak var groupNameLabel: UILabel!  | 
            |
| 17 | 18 | 
                // MARK: Storyboard property  | 
            
| 18 | 
                - @IBOutlet weak var scrollViewConstraint: NSLayoutConstraint!  | 
            |
| 19 | 
                - @IBOutlet weak var groupLockConstraint: NSLayoutConstraint!  | 
            |
| 20 | 
                - @IBOutlet var titleLabel: UILabel!  | 
            |
| 21 | 
                - @IBOutlet var groupNameLabel: UILabel!  | 
            |
| 22 | 
                - @IBOutlet var groupUserCountLabel: UILabel!  | 
            |
| 23 | 
                - @IBOutlet var groupUserHeaderScrollView: UIScrollView!  | 
            |
| 24 | 
                - @IBOutlet var groupLockSwitch: UISwitch!  | 
            |
| 25 | 
                - @IBOutlet var groupLockTip: UILabel!  | 
            |
| 19 | 
                + @IBOutlet weak var groupMemberCountLabel: UILabel!  | 
            |
| 20 | 
                + @IBOutlet weak var groupMemeberView: GroupDetailMemeberView!  | 
            |
| 21 | 
                + @IBOutlet weak var groupLockSwitch: UISwitch!  | 
            |
| 22 | 
                + @IBOutlet weak var groupLockTip: UILabel!  | 
            |
| 26 | 23 | 
                 | 
            
| 27 | 24 | 
                var viewModel: GroupDetailViewModel!  | 
            
| 28 | 
                - // MARK: parameter property  | 
            |
| 29 | 25 | 
                let disposeBag = DisposeBag()  | 
            
| 30 | 
                - // MARK: view function  | 
            |
| 26 | 
                +  | 
            |
| 31 | 27 | 
                     override func viewDidLoad() {
               | 
            
| 32 | 28 | 
                super.viewDidLoad()  | 
            
| 33 | 
                -// rightBarAction = #selector(quit)  | 
            |
| 34 | 
                - configureInterface()  | 
            |
| 29 | 
                + binding()  | 
            |
| 30 | 
                + viewModel.reload()  | 
            |
| 31 | 
                + title = "群资料"  | 
            |
| 32 | 
                + setRightBarButtonItems()  | 
            |
| 35 | 33 | 
                }  | 
            
| 36 | 
                -  | 
            |
| 37 | 
                -    override func viewWillAppear(_ animated: Bool) {
               | 
            |
| 38 | 
                - super.viewWillAppear(true)  | 
            |
| 39 | 
                -// titleWithbackBar = "群资料"  | 
            |
| 34 | 
                +  | 
            |
| 35 | 
                +    func setRightBarButtonItems() {
               | 
            |
| 36 | 
                + let item = UIBarButtonItem(image: UIImage(named: "navigation-right"), target: self, action: #selector(quit))  | 
            |
| 37 | 
                + navigationItem.rightBarButtonItem = item  | 
            |
| 40 | 38 | 
                }  | 
            
| 41 | 
                -  | 
            |
| 42 | 
                - // MARK: init interface  | 
            |
| 43 | 
                -    func configureInterface() {
               | 
            |
| 44 | 
                -  | 
            |
| 45 | 
                -//        groupDetailViewModel.groupDetailData.asObservable().bind {[unowned self] (model) in
               | 
            |
| 46 | 
                -//            if let adminID = model.group?.admin_id {
               | 
            |
| 47 | 
                -// self.groupLockSwitch.isHidden = adminID != SharedUserInfo.userId  | 
            |
| 48 | 
                -//            } else {
               | 
            |
| 49 | 
                -// self.groupLockSwitch.isHidden = true  | 
            |
| 50 | 
                -// }  | 
            |
| 51 | 
                -//  | 
            |
| 52 | 
                -// self.groupNameLabel.text = model.group?.group_name  | 
            |
| 53 | 
                -//            if let count = model.users?.passed_count {
               | 
            |
| 54 | 
                -// self.groupUserCountLabel.text = "\(count)名"  | 
            |
| 55 | 
                -//            } else {
               | 
            |
| 56 | 
                -// self.groupUserCountLabel.text = "0名"  | 
            |
| 57 | 
                -// }  | 
            |
| 58 | 
                -//  | 
            |
| 59 | 
                -//            guard let passUsers = model.users?.passed else {
               | 
            |
| 60 | 
                -// return  | 
            |
| 61 | 
                -// }  | 
            |
| 62 | 
                -// //锁定  | 
            |
| 63 | 
                -//            if let lock = model.group?.group_lock {
               | 
            |
| 64 | 
                -// self.groupLockSwitch.isOn = lock  | 
            |
| 65 | 
                -// self.groupLockTip.text = lock ? "群已锁定,不再允许新成员加入" : "群未锁定,可以邀请新成员加入"  | 
            |
| 66 | 
                -// }  | 
            |
| 67 | 
                -//            let userHead = passUsers.flatMap {[$0.avatar]}
               | 
            |
| 68 | 
                -// self.configureScrollView(userHead: userHead)  | 
            |
| 69 | 
                -// }.disposed(by: disposeBag)  | 
            |
| 70 | 
                -  | 
            |
| 39 | 
                +  | 
            |
| 40 | 
                +    @objc func quit() {
               | 
            |
| 41 | 
                + let alert = AlertController(title: "退出群", message: "退出后将不再能看到群内照片")  | 
            |
| 42 | 
                + alert.addAlertAction(AlertAction(title: "取消", style: .cancel))  | 
            |
| 43 | 
                +        alert.addAlertAction(AlertAction(title: "确定", handler: { _ in
               | 
            |
| 44 | 
                + self.viewModel.quit()  | 
            |
| 45 | 
                + }))  | 
            |
| 46 | 
                + presentController(alert)  | 
            |
| 71 | 47 | 
                }  | 
            
| 48 | 
                +}  | 
            |
| 72 | 49 | 
                 | 
            
| 73 | 
                -    func configureScrollView(userHead: [String]) {
               | 
            |
| 74 | 
                - var count = -1  | 
            |
| 75 | 
                -        let headerUrl = userHead.filter { (_) -> Bool in
               | 
            |
| 76 | 
                - count += 1  | 
            |
| 77 | 
                - return count < 6  | 
            |
| 78 | 
                - }  | 
            |
| 79 | 
                - let userSize = (view.width - 70) / 6  | 
            |
| 80 | 
                - self.scrollViewConstraint.constant = userSize + 12  | 
            |
| 81 | 
                -//        self.groupUserHeaderScrollView.buildImageViews(headerUrl, width: userSize, height: (view.width - 70) / 6, spacing: 10, topSpcing: 0) { (_) in
               | 
            |
| 82 | 
                -  | 
            |
| 83 | 
                -// }  | 
            |
| 84 | 
                -  | 
            |
| 50 | 
                +/// binding UI  | 
            |
| 51 | 
                +fileprivate extension GroupDetailViewController {
               | 
            |
| 52 | 
                +    func binding() {
               | 
            |
| 53 | 
                + bindViewModelToGroupName()  | 
            |
| 54 | 
                + bindViewModelToGroupMemberCount()  | 
            |
| 55 | 
                + bindViewModelToGroupMemeber()  | 
            |
| 56 | 
                + bindViewModelToGroupLock()  | 
            |
| 57 | 
                + bindViewModelToGroupLockSwitch()  | 
            |
| 58 | 
                + bindGroupLockSwitchToGroupLockTip()  | 
            |
| 85 | 59 | 
                }  | 
            
| 86 | 
                -  | 
            |
| 87 | 
                - // MARK: Storyboard button  | 
            |
| 88 | 
                -  | 
            |
| 89 | 
                -    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
               | 
            |
| 90 | 
                -// let navigationController = segue.destination as! UINavigationController  | 
            |
| 91 | 
                -//        if let ctl = navigationController.topViewController as? ChangeGroupNameController {
               | 
            |
| 92 | 
                -// ctl.detailData = groupDetailViewModel.groupDetailData.value  | 
            |
| 93 | 
                -// }  | 
            |
| 94 | 
                -//        if let ctl = navigationController.topViewController as? GroupUserController {
               | 
            |
| 95 | 
                -//            guard let passed = groupDetailViewModel.groupDetailData.value.users?.passed else {
               | 
            |
| 96 | 
                -// return  | 
            |
| 97 | 
                -// }  | 
            |
| 98 | 
                -// ctl.meberData = Variable<[UserModel]>(passed)  | 
            |
| 99 | 
                -// ctl.groupId = groupDetailViewModel.groupDetailData.value.group_id  | 
            |
| 100 | 
                -// }  | 
            |
| 60 | 
                +  | 
            |
| 61 | 
                +    func bindViewModelToGroupName() {
               | 
            |
| 62 | 
                + viewModel.groupName.bind(to: groupNameLabel.rx.text).disposed(by: disposeBag)  | 
            |
| 101 | 63 | 
                }  | 
            
| 102 | 
                -  | 
            |
| 103 | 
                -    @IBAction func showEWM() {
               | 
            |
| 104 | 
                - let ctl = UIStoryboard.groupDetail.instantiateController(ShowGroupQRController.self)  | 
            |
| 105 | 
                -// ctl.data = groupDetailViewModel.groupDetailData.value.group  | 
            |
| 106 | 
                - presentController(ctl)  | 
            |
| 64 | 
                +  | 
            |
| 65 | 
                +    func bindViewModelToGroupMemberCount() {
               | 
            |
| 66 | 
                + viewModel.groupMemberCount.bind(to: groupMemberCountLabel.rx.text).disposed(by: disposeBag)  | 
            |
| 107 | 67 | 
                }  | 
            
| 108 | 
                -  | 
            |
| 109 | 
                -    @objc func quit() {
               | 
            |
| 110 | 
                -// let alert = FFAlertController(title: "", message: "", alertStyle: .actionSheet)  | 
            |
| 111 | 
                -//        alert.addAlertAction(alertAction: DestructiveAlertAction(title: "退出该群", handler: { (alertAction) in
               | 
            |
| 112 | 
                -// let subAlert = FFAlertController(title: "退出群", message: "退出后将不再能看到群内照片", alertStyle: .alert)  | 
            |
| 113 | 
                -// subAlert.addAlertAction(alertAction: CancelAlertAction())  | 
            |
| 114 | 
                -//            subAlert.addAlertAction(alertAction: ConfirmAlertAction(handler: { (alertAction) in
               | 
            |
| 115 | 
                -//                self.groupDetailViewModel.quitQroup(success: {[weak self] in
               | 
            |
| 116 | 
                -//                    if let weakself = self {
               | 
            |
| 117 | 
                -// PhotoLocalStorage.instance.removeLocalData(group_id: weakself.groupId)  | 
            |
| 118 | 
                -// subAlert.dismissController()  | 
            |
| 119 | 
                -// _ = weakself.navigationController?.popToRootViewController(animated: true)  | 
            |
| 120 | 
                -// FFToastView.showToast(inView: UIApplication.shared.keyWindow ?? weakself.view, withText: "退出群成功")  | 
            |
| 121 | 
                -// }  | 
            |
| 122 | 
                -// })  | 
            |
| 123 | 
                -// }))  | 
            |
| 124 | 
                -// self.presentController(subAlert)  | 
            |
| 125 | 
                -// }))  | 
            |
| 126 | 
                -// alert.addAlertAction(alertAction: FFAlertAction(title: "取消", handler: nil))  | 
            |
| 127 | 
                -// presentController(alert)  | 
            |
| 68 | 
                +  | 
            |
| 69 | 
                +    func bindViewModelToGroupMemeber() {
               | 
            |
| 70 | 
                +        viewModel.groupMembers.subscribe(onNext: { self.setupGroupMember(groupMemebers: $0) }).disposed(by: disposeBag)
               | 
            |
| 71 | 
                + }  | 
            |
| 72 | 
                +  | 
            |
| 73 | 
                +    func bindViewModelToGroupLock() {
               | 
            |
| 74 | 
                + viewModel.groupLock.bind(to: groupLockSwitch.rx.value).disposed(by: disposeBag)  | 
            |
| 75 | 
                + }  | 
            |
| 76 | 
                +  | 
            |
| 77 | 
                +    func bindViewModelToGroupLockSwitch() {
               | 
            |
| 78 | 
                +        viewModel.isAdmin.map { !$0 }.bind(to: groupLockSwitch.rx.isHidden).disposed(by: disposeBag)
               | 
            |
| 79 | 
                + }  | 
            |
| 80 | 
                +  | 
            |
| 81 | 
                +    func bindGroupLockSwitchToGroupLockTip() {
               | 
            |
| 82 | 
                +        groupLockSwitch.rx.value.subscribe(onNext: {[weak self] (v) in
               | 
            |
| 83 | 
                +            guard let `self` = self else { return }
               | 
            |
| 84 | 
                + self.groupLockTip.text = v ? "群已锁定,不再允许新成员加入" : "群未锁定,可以邀请新成员加入"  | 
            |
| 85 | 
                + }).disposed(by: disposeBag)  | 
            |
| 128 | 86 | 
                }  | 
            
| 87 | 
                +  | 
            |
| 88 | 
                +    private func setupGroupMember(groupMemebers: [GroupMemberItem]) {
               | 
            |
| 89 | 
                +        groupMemeberView.avatars = groupMemebers.compactMap { $0.avatar }
               | 
            |
| 90 | 
                + }  | 
            |
| 91 | 
                +}  | 
            |
| 129 | 92 | 
                 | 
            
| 93 | 
                +/// storyboard action  | 
            |
| 94 | 
                +extension GroupDetailViewController {
               | 
            |
| 95 | 
                +    @IBAction func navigationToGroupMember(_ sender: UITapGestureRecognizer) {
               | 
            |
| 96 | 
                + viewModel.navigationToGroupMember()  | 
            |
| 97 | 
                + }  | 
            |
| 98 | 
                +  | 
            |
| 99 | 
                +    @IBAction func navigationToGroupNameModification(_ sender: UITapGestureRecognizer) {
               | 
            |
| 100 | 
                + viewModel.navigationToGroupNameModification()  | 
            |
| 101 | 
                + }  | 
            |
| 102 | 
                +  | 
            |
| 103 | 
                +    @IBAction func presentGroupQR(_ sender: UITapGestureRecognizer) {
               | 
            |
| 104 | 
                + let groupItem = viewModel.item.value.group  | 
            |
| 105 | 
                + let alert = AlertViewController(style: .custom(GroupQRView(groupName: groupItem.group_name,  | 
            |
| 106 | 
                + groupAvatar: "Group\(groupItem.group_default_avatar)",  | 
            |
| 107 | 
                + groupQR: "https:pai.ai/g/\(groupItem.group_id)"),  | 
            |
| 108 | 
                + AlertAnimator()) )  | 
            |
| 109 | 
                + presentController(alert)  | 
            |
| 110 | 
                + }  | 
            |
| 111 | 
                +  | 
            |
| 130 | 112 | 
                     @IBAction func changeSwitch() {
               | 
            
| 131 | 
                -// groupDetailViewModel.postLock(isLock: groupLockSwitch.isOn)  | 
            |
| 113 | 
                + viewModel.toggle(isLock: groupLockSwitch.isOn)  | 
            |
| 132 | 114 | 
                }  | 
            
| 133 | 115 | 
                }  | 
            
| 116 | 
                +  | 
            |
| 117 | 
                +extension GroupDetailViewController: NavigationBackViewController {}
               | 
            
                @@ -1,5 +1,5 @@  | 
            ||
| 1 | 1 | 
                //  | 
            
| 2 | 
                -// MemberCell.swift  | 
            |
| 2 | 
                +// GroupMemberCell.swift  | 
            |
| 3 | 3 | 
                // PaiAi  | 
            
| 4 | 4 | 
                //  | 
            
| 5 | 5 | 
                // Created by mac on 16/5/20.  | 
            
                @@ -10,11 +10,11 @@ import UIKit  | 
            ||
| 10 | 10 | 
                import PaiaiDataKit  | 
            
| 11 | 11 | 
                import PaiaiUIKit  | 
            
| 12 | 12 | 
                 | 
            
| 13 | 
                -protocol ReturnIndexPathDelegate: class {
               | 
            |
| 14 | 
                - func renturnIndexPath(_ indexpath: IndexPath)  | 
            |
| 13 | 
                +protocol GroupMemberCellDelegate: class {
               | 
            |
| 14 | 
                + func remove(_ item: GroupMemberItem)  | 
            |
| 15 | 15 | 
                }  | 
            
| 16 | 16 | 
                 | 
            
| 17 | 
                -final class MemberCell: UITableViewCell {
               | 
            |
| 17 | 
                +final class GroupMemberCell: UITableViewCell {
               | 
            |
| 18 | 18 | 
                 | 
            
| 19 | 19 | 
                // MARK: Storyboard property  | 
            
| 20 | 20 | 
                @IBOutlet weak var isManager: UILabel!  | 
            
                @@ -24,32 +24,21 @@ final class MemberCell: UITableViewCell {
               | 
            ||
| 24 | 24 | 
                @IBOutlet weak var uerImage: UIImageView!  | 
            
| 25 | 25 | 
                 | 
            
| 26 | 26 | 
                // MARK: delete property  | 
            
| 27 | 
                - weak var delegate: ReturnIndexPathDelegate?  | 
            |
| 28 | 
                -  | 
            |
| 29 | 
                - // MARK: parameter property  | 
            |
| 30 | 
                - fileprivate var index: IndexPath!  | 
            |
| 31 | 
                -  | 
            |
| 32 | 
                - // MARK: view function  | 
            |
| 33 | 
                -    override func awakeFromNib() {
               | 
            |
| 34 | 
                - super.awakeFromNib()  | 
            |
| 35 | 
                - }  | 
            |
| 36 | 
                -  | 
            |
| 37 | 
                -    override func setSelected(_ selected: Bool, animated: Bool) {
               | 
            |
| 38 | 
                - super.setSelected(selected, animated: animated)  | 
            |
| 39 | 
                - }  | 
            |
| 27 | 
                + weak var delegate: GroupMemberCellDelegate?  | 
            |
| 28 | 
                + var item = GroupMemberItem(json: [:])  | 
            |
| 40 | 29 | 
                 | 
            
| 41 | 30 | 
                // MARK: init interface  | 
            
| 42 | 
                -    func setInfo(_ model: GroupMemberItem, isManage: Bool, indexPath: IndexPath) {
               | 
            |
| 43 | 
                - index = indexPath  | 
            |
| 31 | 
                +    func setInfo(_ model: GroupMemberItem, isAdmin: Bool) {
               | 
            |
| 32 | 
                + item = model  | 
            |
| 44 | 33 | 
                meberName.text = model.nickname  | 
            
| 45 | 
                -// uerImage.setImageWithNullableURL(model.avatar, placeholderImage: defaultAvatar)  | 
            |
| 34 | 
                + uerImage.setImage(model.avatar, placeholder: UIImage.defaultAvatar)  | 
            |
| 46 | 35 | 
                isManager.isHidden = !model.admin  | 
            
| 47 | 
                - deleteConstraint.constant = !isManage || model.admin ? -32 : 12  | 
            |
| 36 | 
                + deleteConstraint.constant = !isAdmin || model.admin ? -32 : 12  | 
            |
| 48 | 37 | 
                }  | 
            
| 49 | 38 | 
                 | 
            
| 50 | 39 | 
                // MARK: Storyboard button  | 
            
| 51 | 40 | 
                     @IBAction func deleteMemberAction(_ sender: UIButton) {
               | 
            
| 52 | 
                - delegate?.renturnIndexPath(index)  | 
            |
| 41 | 
                + delegate?.remove(item)  | 
            |
| 53 | 42 | 
                }  | 
            
| 54 | 43 | 
                 | 
            
| 55 | 44 | 
                }  | 
            
                @@ -1,5 +1,5 @@  | 
            ||
| 1 | 1 | 
                //  | 
            
| 2 | 
                -// GroupMemberController.swift  | 
            |
| 2 | 
                +// GroupMemberViewController.swift  | 
            |
| 3 | 3 | 
                // PaiAi  | 
            
| 4 | 4 | 
                //  | 
            
| 5 | 5 | 
                // Created by zhengjianfei on 16/4/6.  | 
            
                @@ -9,62 +9,58 @@  | 
            ||
| 9 | 9 | 
                import UIKit  | 
            
| 10 | 10 | 
                import RxCocoa  | 
            
| 11 | 11 | 
                import RxSwift  | 
            
| 12 | 
                +import RxDataSources  | 
            |
| 12 | 13 | 
                import PaiaiUIKit  | 
            
| 13 | 14 | 
                import PaiaiDataKit  | 
            
| 14 | 15 | 
                 | 
            
| 15 | 
                -final class GroupMemberController: UIViewController {
               | 
            |
| 16 | 
                +final class GroupMemberViewController: UIViewController {
               | 
            |
| 16 | 17 | 
                 | 
            
| 17 | 
                - // MARK: Storyboard property  | 
            |
| 18 | 
                - @IBOutlet var tableView: UITableView!  | 
            |
| 18 | 
                + @IBOutlet weak var tableView: UITableView!  | 
            |
| 19 | 19 | 
                 | 
            
| 20 | 
                - // MARK: data property  | 
            |
| 21 | 
                - lazy var meberData = Variable<[GroupMemberItem]>([])  | 
            |
| 22 | 
                - var groupMebersViewModel = GroupMemberViewModel()  | 
            |
| 23 | 
                -  | 
            |
| 24 | 
                - // MARK: parameter property  | 
            |
| 25 | 
                - lazy var groupId = ""  | 
            |
| 26 | 
                - lazy var isManage = false  | 
            |
| 20 | 
                + var viewModel: GroupMemberViewModel!  | 
            |
| 27 | 21 | 
                let disposeBag = DisposeBag()  | 
            
| 22 | 
                +  | 
            |
| 28 | 23 | 
                // MARK: view function  | 
            
| 29 | 24 | 
                     override func viewDidLoad() {
               | 
            
| 30 | 25 | 
                super.viewDidLoad()  | 
            
| 31 | 
                - tableView?.rowHeight = 44.0  | 
            |
| 32 | 
                -//        isManage = meberData.value.filter({ (userModel) -> Bool in
               | 
            |
| 33 | 
                -// return userModel.user_id == SharedUserInfo.userId && userModel.admin  | 
            |
| 34 | 
                -// }).count > 0  | 
            |
| 35 | 
                -        meberData.asObservable().bind(to: tableView.rx.items(cellIdentifier: "MemberCell", cellType: MemberCell.self)) { (row, model, cell) in
               | 
            |
| 36 | 
                - cell.setInfo(model, isManage: self.isManage, indexPath :IndexPath(row: row, section: 0))  | 
            |
| 37 | 
                - cell.delegate = self  | 
            |
| 38 | 
                - }.disposed(by: disposeBag)  | 
            |
| 26 | 
                + title = "群成员"  | 
            |
| 27 | 
                + binding()  | 
            |
| 39 | 28 | 
                }  | 
            
| 29 | 
                +}  | 
            |
| 40 | 30 | 
                 | 
            
| 41 | 
                -//    override func backToController() {
               | 
            |
| 42 | 
                -// dismissController()  | 
            |
| 43 | 
                -// }  | 
            |
| 44 | 
                -  | 
            |
| 45 | 
                -    override func viewWillAppear(_ animated: Bool) {
               | 
            |
| 46 | 
                - super.viewWillAppear(true)  | 
            |
| 47 | 
                -// titleWithbackBar = "群成员"  | 
            |
| 31 | 
                +fileprivate extension GroupMemberViewController {
               | 
            |
| 32 | 
                +  | 
            |
| 33 | 
                +    var dataSource: RxTableViewSectionedAnimatedDataSource<AnimatableSectionModel<Int, GroupMemberItem>> {
               | 
            |
| 34 | 
                + return RxTableViewSectionedAnimatedDataSource<AnimatableSectionModel<Int, GroupMemberItem>>(  | 
            |
| 35 | 
                +            configureCell: { (dataSource, tableView, indexPath, item) in
               | 
            |
| 36 | 
                + let cell = tableView.dequeueReusableCell(withIdentifier: "groupMemberCell", for: indexPath) as! GroupMemberCell  | 
            |
| 37 | 
                + cell.setInfo(item, isAdmin: self.viewModel.isAdmin)  | 
            |
| 38 | 
                + cell.delegate = self  | 
            |
| 39 | 
                + return cell  | 
            |
| 40 | 
                + })  | 
            |
| 41 | 
                + }  | 
            |
| 42 | 
                +  | 
            |
| 43 | 
                +    func binding() {
               | 
            |
| 44 | 
                + bindViewModelToTableView()  | 
            |
| 45 | 
                + }  | 
            |
| 46 | 
                +  | 
            |
| 47 | 
                +    func bindViewModelToTableView() {
               | 
            |
| 48 | 
                + viewModel.contents  | 
            |
| 49 | 
                + .bind(to: tableView.rx.items(dataSource: dataSource))  | 
            |
| 50 | 
                + .disposed(by: disposeBag)  | 
            |
| 48 | 51 | 
                }  | 
            
| 49 | 52 | 
                }  | 
            
| 50 | 53 | 
                 | 
            
| 51 | 
                -// MARK: custom delegate  | 
            |
| 52 | 
                -extension GroupMemberController: ReturnIndexPathDelegate {
               | 
            |
| 53 | 
                -  | 
            |
| 54 | 
                -    func renturnIndexPath(_ indexpath: IndexPath) {
               | 
            |
| 55 | 
                -  | 
            |
| 56 | 
                -// let alert = FFAlertController(title: "删除群成员", message: "删除后将不再看见群内照片", alertStyle: .alert)  | 
            |
| 57 | 
                -// alert.addAlertAction(alertAction: CancelAlertAction())  | 
            |
| 58 | 
                -//        alert.addAlertAction(alertAction: ConfirmAlertAction(handler: { (alertAction) in
               | 
            |
| 59 | 
                -// let params: [String: AnyObject] = ["group_id": self.groupId as AnyObject, "admin_id": SharedUserInfo.userId as AnyObject, "user_id": self.meberData.value[indexpath.row].user_id as AnyObject]  | 
            |
| 60 | 
                -//            self.groupMebersViewModel.deleteMeber(params: params, success: {
               | 
            |
| 61 | 
                -// self.meberData.value.remove(at: indexpath.row)  | 
            |
| 62 | 
                -// self.tableView.beginUpdates()  | 
            |
| 63 | 
                -// self.tableView.deleteRows(at: [indexpath], with: UITableViewRowAnimation.left)  | 
            |
| 64 | 
                -// self.tableView.endUpdates()  | 
            |
| 65 | 
                -// })  | 
            |
| 66 | 
                -// }))  | 
            |
| 67 | 
                -// presentController(alert)  | 
            |
| 54 | 
                +extension GroupMemberViewController: GroupMemberCellDelegate {
               | 
            |
| 55 | 
                +    func remove(_ item: GroupMemberItem) {
               | 
            |
| 56 | 
                + let alert = AlertController(title: "删除群成员", message: "删除后将不再看见群内照片")  | 
            |
| 57 | 
                + alert.addAlertAction(AlertAction(title: "取消", style: .cancel))  | 
            |
| 58 | 
                +        alert.addAlertAction(AlertAction(title: "确定", handler: {(_) in
               | 
            |
| 59 | 
                + self.viewModel.removeMember(item)  | 
            |
| 60 | 
                + }))  | 
            |
| 61 | 
                +  | 
            |
| 62 | 
                + presentController(alert)  | 
            |
| 68 | 63 | 
                }  | 
            
| 69 | 
                -  | 
            |
| 70 | 64 | 
                }  | 
            
| 65 | 
                +  | 
            |
| 66 | 
                +extension GroupMemberViewController: NavigationBackViewController {}
               | 
            
                @@ -1,5 +1,5 @@  | 
            ||
| 1 | 1 | 
                //  | 
            
| 2 | 
                -// ChangeGroupNameController.swift  | 
            |
| 2 | 
                +// GroupNameModificationViewController.swift  | 
            |
| 3 | 3 | 
                // PaiAi  | 
            
| 4 | 4 | 
                //  | 
            
| 5 | 5 | 
                // Created by zhengjianfei on 16/4/6.  | 
            
                @@ -12,79 +12,79 @@ import RxCocoa  | 
            ||
| 12 | 12 | 
                import PaiaiUIKit  | 
            
| 13 | 13 | 
                import PaiaiDataKit  | 
            
| 14 | 14 | 
                 | 
            
| 15 | 
                -final class ChangeGroupNameController: UIViewController {
               | 
            |
| 15 | 
                +final class GroupNameModificationViewController: UIViewController {
               | 
            |
| 16 | 16 | 
                 | 
            
| 17 | 17 | 
                // MARK: Storyboard property  | 
            
| 18 | 
                - @IBOutlet var textField: UITextField!  | 
            |
| 18 | 
                + @IBOutlet weak var textField: UITextField!  | 
            |
| 19 | 19 | 
                @IBOutlet weak var saveButton: UIButton!  | 
            
| 20 | 
                -  | 
            |
| 21 | 
                - // MARK: data property  | 
            |
| 22 | 
                -// var detailData: GroupDetailModel?  | 
            |
| 20 | 
                +  | 
            |
| 21 | 
                + var item = GroupDetailItem(json: [:])  | 
            |
| 22 | 
                +  | 
            |
| 23 | 23 | 
                let disposeBag = DisposeBag()  | 
            
| 24 | 24 | 
                // MARK: view function  | 
            
| 25 | 25 | 
                     override func viewDidLoad() {
               | 
            
| 26 | 26 | 
                super.viewDidLoad()  | 
            
| 27 | 
                - configureTextField()  | 
            |
| 27 | 
                + title = "群名称"  | 
            |
| 28 | 
                + setupTextFieldLeftView()  | 
            |
| 29 | 
                + bindTextFieldToSaveButton()  | 
            |
| 28 | 30 | 
                }  | 
            
| 29 | 
                -  | 
            |
| 30 | 
                -    override func viewWillAppear(_ animated: Bool) {
               | 
            |
| 31 | 
                - super.viewWillAppear(true)  | 
            |
| 32 | 
                -// titleWithbackBar = "群名称"  | 
            |
| 31 | 
                +  | 
            |
| 32 | 
                +    func setupTextFieldLeftView() {
               | 
            |
| 33 | 
                + let leftView = UIView(frame: CGRect(x: 0, y: 0, width: 12, height: textField.width))  | 
            |
| 34 | 
                + textField.leftView = leftView  | 
            |
| 35 | 
                + textField.leftViewMode = .always  | 
            |
| 36 | 
                + textField.placeholder = item.group.group_name  | 
            |
| 33 | 37 | 
                }  | 
            
| 34 | 38 | 
                 | 
            
| 35 | 
                -//    override func backToController() {
               | 
            |
| 36 | 
                -// dismissController()  | 
            |
| 37 | 
                -// }  | 
            |
| 38 | 
                -  | 
            |
| 39 | 
                -    func configureTextField() {
               | 
            |
| 40 | 
                -        do {
               | 
            |
| 41 | 
                - let view = UIView(frame: CGRect(x: 0, y: 0, width: 12, height: textField.width))  | 
            |
| 42 | 
                - textField.leftView = view  | 
            |
| 43 | 
                - textField.leftViewMode = .always  | 
            |
| 44 | 
                -// textField.placeholder = detailData?.group?.group_name  | 
            |
| 45 | 
                - }  | 
            |
| 46 | 
                -  | 
            |
| 47 | 
                -        do {
               | 
            |
| 48 | 
                - textField.rx.text  | 
            |
| 49 | 
                -                        .map {!($0?.isEmpty)!}
               | 
            |
| 50 | 
                - .bind(to: saveButton.rx.isEnabled)  | 
            |
| 51 | 
                - .disposed(by: disposeBag)  | 
            |
| 52 | 
                - }  | 
            |
| 39 | 
                +    func bindTextFieldToSaveButton() {
               | 
            |
| 40 | 
                + textField.rx.text  | 
            |
| 41 | 
                +                    .map {!($0?.isEmpty)!}
               | 
            |
| 42 | 
                + .bind(to: saveButton.rx.isEnabled)  | 
            |
| 43 | 
                + .disposed(by: disposeBag)  | 
            |
| 53 | 44 | 
                }  | 
            
| 45 | 
                +}  | 
            |
| 54 | 46 | 
                 | 
            
| 55 | 
                - // MARK: Storyboard button  | 
            |
| 47 | 
                +extension GroupNameModificationViewController {
               | 
            |
| 48 | 
                +  | 
            |
| 56 | 49 | 
                     @IBAction func saveName() {
               | 
            
| 57 | 
                -        guard NSString(string: textField.text ?? "").length < 20 else {
               | 
            |
| 58 | 
                - jumpToSaveFailController()  | 
            |
| 50 | 
                +        if (textField.text ?? "").count > 20 {
               | 
            |
| 51 | 
                + saveFailed()  | 
            |
| 59 | 52 | 
                return  | 
            
| 60 | 53 | 
                }  | 
            
| 61 | 
                -//        guard let info = detailData else {
               | 
            |
| 62 | 
                -// return  | 
            |
| 63 | 
                -// }  | 
            |
| 64 | 
                -//        guard let group = detailData?.group else {
               | 
            |
| 65 | 
                -// return  | 
            |
| 66 | 
                -// }  | 
            |
| 67 | 
                -// let params = ["group_id": info.group_id,  | 
            |
| 68 | 
                -// "admin_id": group.admin_id, "group_name": textField.text ?? ""] as [String: AnyObject]  | 
            |
| 69 | 
                -// let request = StatusNetworkRequest(param: params, path: .groupUpdate)  | 
            |
| 70 | 
                -//        NetworkApi.share.post(request: request) { (res) in
               | 
            |
| 71 | 
                -//            guard res.status == 200 else {
               | 
            |
| 72 | 
                -// return  | 
            |
| 73 | 
                -// }  | 
            |
| 74 | 
                -// addGroupInfoToRecent(group)  | 
            |
| 75 | 
                -// FFToastView.showToast(inView: self.view, withText: "保存成功")  | 
            |
| 76 | 
                -// self.textField.resignFirstResponder()  | 
            |
| 77 | 
                -// }  | 
            |
| 54 | 
                +  | 
            |
| 55 | 
                +  | 
            |
| 56 | 
                +  | 
            |
| 57 | 
                +        //        guard let info = detailData else {
               | 
            |
| 58 | 
                + // return  | 
            |
| 59 | 
                + // }  | 
            |
| 60 | 
                +        //        guard let group = detailData?.group else {
               | 
            |
| 61 | 
                + // return  | 
            |
| 62 | 
                + // }  | 
            |
| 63 | 
                + // let params = ["group_id": info.group_id,  | 
            |
| 64 | 
                + // "admin_id": group.admin_id, "group_name": textField.text ?? ""] as [String: AnyObject]  | 
            |
| 65 | 
                + // let request = StatusNetworkRequest(param: params, path: .groupUpdate)  | 
            |
| 66 | 
                +        //        NetworkApi.share.post(request: request) { (res) in
               | 
            |
| 67 | 
                +        //            guard res.status == 200 else {
               | 
            |
| 68 | 
                + // return  | 
            |
| 69 | 
                + // }  | 
            |
| 70 | 
                + // addGroupInfoToRecent(group)  | 
            |
| 71 | 
                + // FFToastView.showToast(inView: self.view, withText: "保存成功")  | 
            |
| 72 | 
                + // self.textField.resignFirstResponder()  | 
            |
| 73 | 
                + // }  | 
            |
| 78 | 74 | 
                }  | 
            
| 79 | 
                -  | 
            |
| 80 | 
                -    func jumpToSaveFailController() {
               | 
            |
| 75 | 
                +  | 
            |
| 76 | 
                +    func saveFailed() {
               | 
            |
| 81 | 77 | 
                textField.resignFirstResponder()  | 
            
| 82 | 
                -// let alert = FFAlertController(title: "保存失败", message: "群名称不能超过20个字", alertStyle: .alert)  | 
            |
| 83 | 
                -// alert.addAlertAction(alertAction: ConfirmAlertAction(handler: nil))  | 
            |
| 84 | 
                -// presentController(alert)  | 
            |
| 78 | 
                + let alert = AlertController(title: "保存失败", message: "群名称不能超过20个字")  | 
            |
| 79 | 
                + alert.addAlertAction(AlertAction(title: "确定"))  | 
            |
| 80 | 
                + presentController(alert)  | 
            |
| 85 | 81 | 
                }  | 
            
| 86 | 82 | 
                 | 
            
| 83 | 
                +  | 
            |
| 87 | 84 | 
                     @IBAction func tapView() {
               | 
            
| 88 | 85 | 
                textField.resignFirstResponder()  | 
            
| 89 | 86 | 
                }  | 
            
| 90 | 87 | 
                }  | 
            
| 88 | 
                +  | 
            |
| 89 | 
                +  | 
            |
| 90 | 
                +extension GroupNameModificationViewController: NavigationBackViewController {}
               | 
            
                @@ -17,7 +17,7 @@ import PullToRefresh  | 
            ||
| 17 | 17 | 
                 final class GroupViewController: UIViewController {
               | 
            
| 18 | 18 | 
                 | 
            
| 19 | 19 | 
                // MARK: Storyboard property  | 
            
| 20 | 
                - @IBOutlet var collectionView: UICollectionView!  | 
            |
| 20 | 
                + @IBOutlet weak var collectionView: UICollectionView!  | 
            |
| 21 | 21 | 
                @IBOutlet weak var photographBtn: UIButton!  | 
            
| 22 | 22 | 
                 | 
            
| 23 | 23 | 
                // MARK: custom UI property  | 
            
                @@ -43,7 +43,6 @@ final class GroupViewController: UIViewController {
               | 
            ||
| 43 | 43 | 
                 | 
            
| 44 | 44 | 
                // MARK: data property  | 
            
| 45 | 45 | 
                var viewModel: GroupViewModel!  | 
            
| 46 | 
                - var groupItem: GroupItem!  | 
            |
| 47 | 46 | 
                 | 
            
| 48 | 47 | 
                fileprivate var navigationViewNotReady = true  | 
            
| 49 | 48 | 
                fileprivate let disposeBag = DisposeBag()  | 
            
                @@ -113,19 +112,23 @@ fileprivate extension GroupViewController {
               | 
            ||
| 113 | 112 | 
                }  | 
            
| 114 | 113 | 
                 | 
            
| 115 | 114 | 
                     func bindCollectionViewToViewModel() {
               | 
            
| 116 | 
                - collectionView.rx.modelSelected(PhotoItem.self)  | 
            |
| 115 | 
                + collectionView.rx.itemSelected  | 
            |
| 117 | 116 | 
                .asDriver()  | 
            
| 118 | 
                -            .drive(onNext: { [unowned self] in self.viewModel.didSelect($0) })
               | 
            |
| 117 | 
                +            .drive(onNext: { [unowned self] in self.viewModel.didSelect($0.item) })
               | 
            |
| 119 | 118 | 
                .disposed(by: disposeBag)  | 
            
| 120 | 119 | 
                }  | 
            
| 121 | 120 | 
                 | 
            
| 122 | 121 | 
                     func bindViewModelToNavigationBarTitle() {
               | 
            
| 123 | 
                - navigationBarViewTitle.text = groupItem.group_name  | 
            |
| 122 | 
                + viewModel.groupName.bind(to: navigationBarViewTitle.rx.text).disposed(by: disposeBag)  | 
            |
| 124 | 123 | 
                }  | 
            
| 125 | 124 | 
                 | 
            
| 126 | 125 | 
                     func bindViewModelToNavigationBarImage() {
               | 
            
| 127 | 
                - navigationBarViewImage.setImage(groupItem.group_avatar,  | 
            |
| 128 | 
                - placeholder: UIImage(named: "Group\(groupItem.group_default_avatar)"))  | 
            |
| 126 | 
                + viewModel.groupAvatar  | 
            |
| 127 | 
                +            .subscribe(onNext: {[weak self] (avatar) in
               | 
            |
| 128 | 
                +                guard let `self` = self else { return }
               | 
            |
| 129 | 
                + self.navigationBarViewImage.image = UIImage(named: avatar)  | 
            |
| 130 | 
                + }).disposed(by: disposeBag)  | 
            |
| 131 | 
                +  | 
            |
| 129 | 132 | 
                }  | 
            
| 130 | 133 | 
                }  | 
            
| 131 | 134 | 
                 | 
            
                @@ -160,6 +163,8 @@ extension GroupViewController: NavigationBarInteractiveViewController {
               | 
            ||
| 160 | 163 | 
                }  | 
            
| 161 | 164 | 
                 | 
            
| 162 | 165 | 
                     @objc func presentGroupQR() {
               | 
            
| 166 | 
                +  | 
            |
| 167 | 
                + let groupItem = viewModel.groupItem.value  | 
            |
| 163 | 168 | 
                let alert = AlertViewController(style: .custom(GroupQRView(groupName: groupItem.group_name,  | 
            
| 164 | 169 | 
                groupAvatar: "Group\(groupItem.group_default_avatar)",  | 
            
| 165 | 170 | 
                groupQR: "https:pai.ai/g/\(groupItem.group_id)"),  | 
            
                @@ -211,10 +216,6 @@ fileprivate extension GroupViewController {
               | 
            ||
| 211 | 216 | 
                }  | 
            
| 212 | 217 | 
                }  | 
            
| 213 | 218 | 
                 | 
            
| 214 | 
                -extension GroupViewController {
               | 
            |
| 215 | 
                -  | 
            |
| 216 | 
                -}  | 
            |
| 217 | 
                -  | 
            |
| 218 | 219 | 
                 extension GroupViewController: UICollectionViewDelegateFlowLayout {
               | 
            
| 219 | 220 | 
                func collectionView(_ collectionView: UICollectionView,  | 
            
| 220 | 221 | 
                layout collectionViewLayout: UICollectionViewLayout,  | 
            
                @@ -7,67 +7,52 @@  | 
            ||
| 7 | 7 | 
                //  | 
            
| 8 | 8 | 
                 | 
            
| 9 | 9 | 
                import UIKit  | 
            
| 10 | 
                -import RxSwift  | 
            |
| 11 | 10 | 
                import PaiaiDataKit  | 
            
| 12 | 11 | 
                import PaiaiUIKit  | 
            
| 13 | 12 | 
                 | 
            
| 14 | 13 | 
                 | 
            
| 15 | 14 | 
                 final class CreateGroupConfirmViewController: AlertViewController {
               | 
            
| 15 | 
                +  | 
            |
| 16 | 
                +    override var animationView: UIView? {
               | 
            |
| 17 | 
                + return tipView  | 
            |
| 18 | 
                + }  | 
            |
| 19 | 
                +  | 
            |
| 16 | 20 | 
                // MARK: Storyboard property  | 
            
| 17 | 
                - @IBOutlet var tipView: UIView!  | 
            |
| 18 | 
                - @IBOutlet var nameLabel: UILabel!  | 
            |
| 19 | 
                - @IBOutlet var imageView: UIImageView!  | 
            |
| 21 | 
                + @IBOutlet weak var tipView: UIView!  | 
            |
| 22 | 
                + @IBOutlet weak var nameLabel: UILabel!  | 
            |
| 23 | 
                + @IBOutlet weak var imageView: UIImageView!  | 
            |
| 20 | 24 | 
                 | 
            
| 21 | 
                - var viewModel = CreateGroupConfirmViewModel()  | 
            |
| 22 | 
                - var disposeBag = DisposeBag()  | 
            |
| 25 | 
                + var viewModel: CreateGroupViewModel!  | 
            |
| 23 | 26 | 
                 | 
            
| 24 | 27 | 
                     override func viewDidLoad() {
               | 
            
| 25 | 28 | 
                super.viewDidLoad()  | 
            
| 26 | 
                - configurationRx()  | 
            |
| 27 | 
                - }  | 
            |
| 28 | 
                -  | 
            |
| 29 | 
                -    func configurationRx() {
               | 
            |
| 30 | 
                - viewModel.name.bind(to: nameLabel.rx.text).disposed(by: disposeBag)  | 
            |
| 29 | 
                + binding()  | 
            |
| 31 | 30 | 
                }  | 
            
| 32 | 
                -  | 
            |
| 33 | 
                - // MARK: Storyboard button function  | 
            |
| 31 | 
                +}  | 
            |
| 32 | 
                +  | 
            |
| 33 | 
                +/// storyboard button action  | 
            |
| 34 | 
                +extension CreateGroupConfirmViewController {
               | 
            |
| 34 | 35 | 
                     @IBAction func confirmAction() {
               | 
            
| 35 | 
                - self.viewModel.createGroup()  | 
            |
| 36 | 
                + viewModel.createGroup()  | 
            |
| 36 | 37 | 
                }  | 
            
| 37 | 38 | 
                 | 
            
| 38 | 
                -    override var animationView: UIView? {
               | 
            |
| 39 | 
                - return tipView  | 
            |
| 40 | 
                - }  | 
            |
| 41 | 
                -  | 
            |
| 42 | 
                -//    func createGroup(_ name: String, avatar: Int) {
               | 
            |
| 43 | 
                -// let params = ["user_id": SharedUserInfo.userId, "group_name": name, "group_default_avatar": avatar] as [String: AnyObject]  | 
            |
| 44 | 
                -// FFToastView.showLoadingToast(inView: view, blockSuperView: true)  | 
            |
| 45 | 
                -//// let request = CommonNetworkRequest<GroupModel>(param: params, path: .groupCreate)  | 
            |
| 46 | 
                -////        NetworkApi.share.post(request: request) {[weak self] (res) in
               | 
            |
| 47 | 
                -////            guard let weakself = self else {
               | 
            |
| 48 | 
                -//// return  | 
            |
| 49 | 
                -//// }  | 
            |
| 50 | 
                -//// weakself.group = res.first ?? GroupModel()  | 
            |
| 51 | 
                -//// weakself.confirmAndJump()  | 
            |
| 52 | 
                -////  | 
            |
| 53 | 
                -//// }  | 
            |
| 54 | 
                -// }  | 
            |
| 55 | 
                -  | 
            |
| 56 | 
                -//    func confirmAndJump() {
               | 
            |
| 57 | 
                -// let ctl = UIStoryboard.main.instantiateController(GroupViewController.self)  | 
            |
| 58 | 
                -// ctl.groupModel = group  | 
            |
| 59 | 
                -// ctl.isCreate = true  | 
            |
| 60 | 
                -//        guard let parentController = presentingViewController as? UINavigationController else {
               | 
            |
| 61 | 
                -// return  | 
            |
| 62 | 
                -// }  | 
            |
| 63 | 
                -//        guard let rootController = parentController.viewControllers.first as? HomeViewController else {
               | 
            |
| 64 | 
                -// return  | 
            |
| 65 | 
                -// }  | 
            |
| 66 | 
                -// dismissController()  | 
            |
| 67 | 
                -// rootController.navigationController?.pushViewController(ctl, animated: true)  | 
            |
| 68 | 
                -// }  | 
            |
| 69 | 
                -  | 
            |
| 70 | 39 | 
                     @IBAction func cancelAction() {
               | 
            
| 71 | 40 | 
                dismissController()  | 
            
| 72 | 41 | 
                }  | 
            
| 73 | 42 | 
                }  | 
            
| 43 | 
                +  | 
            |
| 44 | 
                +/// binding UI  | 
            |
| 45 | 
                +extension CreateGroupConfirmViewController {
               | 
            |
| 46 | 
                +    func binding() {
               | 
            |
| 47 | 
                + bindGroupName()  | 
            |
| 48 | 
                + bindGroupAvatar()  | 
            |
| 49 | 
                + }  | 
            |
| 50 | 
                +  | 
            |
| 51 | 
                +    func bindGroupName() {
               | 
            |
| 52 | 
                + nameLabel.text = viewModel.name  | 
            |
| 53 | 
                + }  | 
            |
| 54 | 
                +  | 
            |
| 55 | 
                +    func bindGroupAvatar() {
               | 
            |
| 56 | 
                + imageView.image = UIImage(named: viewModel.avatar)  | 
            |
| 57 | 
                + }  | 
            |
| 58 | 
                +}  | 
            
                @@ -35,7 +35,7 @@ final class CreateGroupViewController: AlertViewController {
               | 
            ||
| 35 | 35 | 
                // MARK: view function  | 
            
| 36 | 36 | 
                     override func viewDidLoad() {
               | 
            
| 37 | 37 | 
                super.viewDidLoad()  | 
            
| 38 | 
                - contentHeightConstraint.constant = 48 + 44 * CGFloat(RecentGroupInfo.share.count + 1)  | 
            |
| 38 | 
                + contentHeightConstraint.constant = 48 + 44 * CGFloat(ShareRecentGroupInfo.count + 1)  | 
            |
| 39 | 39 | 
                }  | 
            
| 40 | 40 | 
                 | 
            
| 41 | 41 | 
                // MARK: Storyboard button function  | 
            
                @@ -50,7 +50,7 @@ extension CreateGroupViewController: UITableViewDataSource, UITableViewDelegate  | 
            ||
| 50 | 50 | 
                }  | 
            
| 51 | 51 | 
                 | 
            
| 52 | 52 | 
                     func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
               | 
            
| 53 | 
                - return RecentGroupInfo.share.count + 1  | 
            |
| 53 | 
                + return ShareRecentGroupInfo.count + 1  | 
            |
| 54 | 54 | 
                }  | 
            
| 55 | 55 | 
                 | 
            
| 56 | 56 | 
                     func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
               | 
            
                @@ -59,7 +59,7 @@ extension CreateGroupViewController: UITableViewDataSource, UITableViewDelegate  | 
            ||
| 59 | 59 | 
                case 0:  | 
            
| 60 | 60 | 
                self.delegate?.navigateToCreateGroupConfirm()  | 
            
| 61 | 61 | 
                default:  | 
            
| 62 | 
                - self.delegate?.didSelect(RecentGroupInfo.share[indexPath.row - 1])  | 
            |
| 62 | 
                + self.delegate?.didSelect(ShareRecentGroupInfo[indexPath.row - 1])  | 
            |
| 63 | 63 | 
                }  | 
            
| 64 | 64 | 
                }  | 
            
| 65 | 65 | 
                 | 
            
                @@ -70,9 +70,9 @@ extension CreateGroupViewController: UITableViewDataSource, UITableViewDelegate  | 
            ||
| 70 | 70 | 
                return cell  | 
            
| 71 | 71 | 
                default:  | 
            
| 72 | 72 | 
                let cell = tableView.dequeueReusableCell(withIdentifier: "RecentCell", for: indexPath)  | 
            
| 73 | 
                -// let group =  | 
            |
| 74 | 
                -//            (cell.viewWithTag(90) as? UILabel).flatMap {$0}?.text = group.group_name
               | 
            |
| 75 | 
                -//            (cell.viewWithTag(90) as? UIImageView).flatMap {$0}?.setImageWithNullableURL(group.group_avatar, placeholderImage: UIImage(named: "Group\(group.group_default_avatar)"))
               | 
            |
| 73 | 
                + let group = ShareRecentGroupInfo[indexPath.row - 1]  | 
            |
| 74 | 
                + cell.textLabel?.text = group.group_name  | 
            |
| 75 | 
                + cell.imageView?.setImage(group.group_avatar, placeholder: UIImage(named: "Group\(group.group_default_avatar)"))  | 
            |
| 76 | 76 | 
                 | 
            
| 77 | 77 | 
                return cell  | 
            
| 78 | 78 | 
                }  | 
            
                @@ -11,12 +11,24 @@ import PaiaiDataKit  | 
            ||
| 11 | 11 | 
                import PaiaiUIKit  | 
            
| 12 | 12 | 
                 | 
            
| 13 | 13 | 
                 class HomeCoordinator: Coordinator {
               | 
            
| 14 | 
                +    fileprivate enum CoordinatorKey: String {
               | 
            |
| 15 | 
                + case home = "home"  | 
            |
| 16 | 
                + case message = "message"  | 
            |
| 17 | 
                + case mine = "mine"  | 
            |
| 18 | 
                + case photoDetail = "photoDetail"  | 
            |
| 19 | 
                + case group = "group"  | 
            |
| 20 | 
                + }  | 
            |
| 21 | 
                + fileprivate var coordinators = [CoordinatorKey: Coordinator]()  | 
            |
| 14 | 22 | 
                 | 
            
| 15 | 23 | 
                var homeViewController: HomeViewController  | 
            
| 24 | 
                + var navigationController: UINavigationController  | 
            |
| 16 | 25 | 
                var shareUserInfoViewModel: UserInfoViewModel  | 
            
| 17 | 26 | 
                 | 
            
| 18 | 
                -    init(_ homeVC: HomeViewController, userInfoViewModel: UserInfoViewModel) {
               | 
            |
| 27 | 
                + init(_ homeVC: HomeViewController,  | 
            |
| 28 | 
                + navigationController: UINavigationController,  | 
            |
| 29 | 
                +         userInfoViewModel: UserInfoViewModel) {
               | 
            |
| 19 | 30 | 
                homeViewController = homeVC  | 
            
| 31 | 
                + self.navigationController = navigationController  | 
            |
| 20 | 32 | 
                shareUserInfoViewModel = userInfoViewModel  | 
            
| 21 | 33 | 
                homeViewController.viewModel.delegate = self  | 
            
| 22 | 34 | 
                }  | 
            
                @@ -27,9 +39,14 @@ class HomeCoordinator: Coordinator {
               | 
            ||
| 27 | 39 | 
                }  | 
            
| 28 | 40 | 
                 | 
            
| 29 | 41 | 
                 extension HomeCoordinator: HomeViewModelDelegate {
               | 
            
| 30 | 
                -    func didSelect(_ item: PhotoItem) {
               | 
            |
| 31 | 
                - let ctl = UIStoryboard.photoDetail.instantiateController(DetailPageController.self)  | 
            |
| 32 | 
                - homeViewController.pushController(ctl)  | 
            |
| 42 | 
                +    func didSelect(_ items: [PhotoItem], currIndex: Int) {
               | 
            |
| 43 | 
                + let ctl = UIStoryboard.photoDetail.instantiateController(PhotoDetailViewController.self)  | 
            |
| 44 | 
                + let coordinator = PhotoDetailCoordinator(ctl, nav: navigationController,  | 
            |
| 45 | 
                + viewModel: PhotoDetailViewModel(item: items[currIndex]),  | 
            |
| 46 | 
                + listViewModel: PhotoDetailListViewModel(items: items, currIndex: currIndex))  | 
            |
| 47 | 
                + coordinators[.photoDetail] = coordinator  | 
            |
| 48 | 
                + coordinator.start()  | 
            |
| 49 | 
                + navigationController.pushViewController(coordinator.photoDetailViewController)  | 
            |
| 33 | 50 | 
                }  | 
            
| 34 | 51 | 
                 | 
            
| 35 | 52 | 
                     func createGroup() {
               | 
            
                @@ -46,16 +63,36 @@ extension HomeCoordinator: HomeViewModelDelegate {
               | 
            ||
| 46 | 63 | 
                 | 
            
| 47 | 64 | 
                 extension HomeCoordinator: CreateGroupViewControllerDelegate {
               | 
            
| 48 | 65 | 
                     func didSelect(_ item: GroupItem) {
               | 
            
| 49 | 
                -// let ctl = UIStoryboard.  | 
            |
| 66 | 
                + let ctl = UIStoryboard.group.instantiateController(GroupViewController.self)  | 
            |
| 67 | 
                + ctl.viewModel = GroupViewModel(groupItem: item)  | 
            |
| 68 | 
                + let coordinator = GroupCoordinator(ctl,  | 
            |
| 69 | 
                + navigationController: navigationController)  | 
            |
| 70 | 
                + coordinators[.group] = coordinator  | 
            |
| 71 | 
                + navigationController.pushViewController(ctl)  | 
            |
| 50 | 72 | 
                }  | 
            
| 51 | 
                -  | 
            |
| 73 | 
                +  | 
            |
| 52 | 74 | 
                     func navigateToCreateGroupConfirm() {
               | 
            
| 53 | 75 | 
                let ctl = UIStoryboard.main.instantiateCreateGroupConfirmViewController()  | 
            
| 54 | 
                -  | 
            |
| 76 | 
                + ctl.viewModel = CreateGroupViewModel(userInfoViewModel: shareUserInfoViewModel)  | 
            |
| 77 | 
                + ctl.viewModel.delegate = self  | 
            |
| 55 | 78 | 
                homeViewController.presentController(ctl)  | 
            
| 56 | 79 | 
                }  | 
            
| 57 | 80 | 
                }  | 
            
| 58 | 81 | 
                 | 
            
| 82 | 
                +extension HomeCoordinator: CreateGroupViewModelDelegate {
               | 
            |
| 83 | 
                +    func navigationToGroup(_ item: GroupItem) {
               | 
            |
| 84 | 
                +        guard let vc = homeViewController.presentedViewController, vc.isMember(of: CreateGroupConfirmViewController.self) else { return }
               | 
            |
| 85 | 
                + vc.dismissController()  | 
            |
| 86 | 
                +  | 
            |
| 87 | 
                + let ctl = UIStoryboard.group.instantiateController(GroupViewController.self)  | 
            |
| 88 | 
                + let coordinator = GroupCoordinator(ctl,  | 
            |
| 89 | 
                + navigationController: navigationController)  | 
            |
| 90 | 
                + coordinators[.group] = coordinator  | 
            |
| 91 | 
                + ctl.viewModel = GroupViewModel(groupItem: item)  | 
            |
| 92 | 
                + navigationController.pushViewController(ctl)  | 
            |
| 93 | 
                + }  | 
            |
| 94 | 
                +}  | 
            |
| 95 | 
                +  | 
            |
| 59 | 96 | 
                 extension UIStoryboard {
               | 
            
| 60 | 97 | 
                     fileprivate func instantiateCreateGroupViewController() -> CreateGroupViewController {
               | 
            
| 61 | 98 | 
                let createGroupVC = instantiateController(CreateGroupViewController.self)  | 
            
                @@ -120,9 +120,9 @@ fileprivate extension HomeViewController {
               | 
            ||
| 120 | 120 | 
                             .drive(onNext: { [unowned self] in self.preload(indexPath: $0.at) })
               | 
            
| 121 | 121 | 
                .disposed(by: disposeBag)  | 
            
| 122 | 122 | 
                 | 
            
| 123 | 
                - collectionView.rx.modelSelected(PhotoItem.self)  | 
            |
| 124 | 
                - .asDriver()  | 
            |
| 125 | 
                -            .drive(onNext: { [unowned self] in self.viewModel.didSelect($0) })
               | 
            |
| 123 | 
                + collectionView.rx.itemSelected  | 
            |
| 124 | 
                + .asDriver(onErrorJustReturn: IndexPath(item: 0, section: 0))  | 
            |
| 125 | 
                +            .drive(onNext: { [unowned self] in self.viewModel.didSelect($0.row) } )
               | 
            |
| 126 | 126 | 
                .disposed(by: disposeBag)  | 
            
| 127 | 127 | 
                }  | 
            
| 128 | 128 | 
                 | 
            
                @@ -14,8 +14,8 @@ import PaiaiUIKit  | 
            ||
| 14 | 14 | 
                 final class ScanQRViewController: UIViewController {
               | 
            
| 15 | 15 | 
                 | 
            
| 16 | 16 | 
                // MARK: Storyboard property  | 
            
| 17 | 
                - @IBOutlet var scanView: QRCodeScanView!  | 
            |
| 18 | 
                - @IBOutlet var lightLabel: UILabel!  | 
            |
| 17 | 
                + @IBOutlet weak var scanView: QRCodeScanView!  | 
            |
| 18 | 
                + @IBOutlet weak var lightLabel: UILabel!  | 
            |
| 19 | 19 | 
                 | 
            
| 20 | 20 | 
                // MARK: parameter property  | 
            
| 21 | 21 | 
                var viewModel = ScanQRViewModel()  | 
            
                @@ -14,10 +14,10 @@ import RxSwift  | 
            ||
| 14 | 14 | 
                 | 
            
| 15 | 15 | 
                 final class LoginViewController: UIViewController {
               | 
            
| 16 | 16 | 
                 | 
            
| 17 | 
                - @IBOutlet var pageControl: UIPageControl!  | 
            |
| 18 | 
                - @IBOutlet var scrollView: UIScrollView!  | 
            |
| 19 | 
                - @IBOutlet var guestLoginBtn: UIButton!  | 
            |
| 20 | 
                - @IBOutlet var weixinLoginBtn: UIButton!  | 
            |
| 17 | 
                + @IBOutlet weak var pageControl: UIPageControl!  | 
            |
| 18 | 
                + @IBOutlet weak var scrollView: UIScrollView!  | 
            |
| 19 | 
                + @IBOutlet weak var guestLoginBtn: UIButton!  | 
            |
| 20 | 
                + @IBOutlet weak var weixinLoginBtn: UIButton!  | 
            |
| 21 | 21 | 
                 | 
            
| 22 | 22 | 
                public var userInfoViewModel: UserInfoViewModel!  | 
            
| 23 | 23 | 
                 | 
            
                @@ -1,10 +1,6 @@  | 
            ||
| 1 | 1 | 
                <?xml version="1.0" encoding="UTF-8"?>  | 
            
| 2 | 2 | 
                <document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14460.31" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useSafeAreas="YES" colorMatched="YES">  | 
            
| 3 | 
                - <device id="retina4_7" orientation="portrait">  | 
            |
| 4 | 
                - <adaptation id="fullscreen"/>  | 
            |
| 5 | 
                - </device>  | 
            |
| 6 | 3 | 
                <dependencies>  | 
            
| 7 | 
                - <deployment identifier="iOS"/>  | 
            |
| 8 | 4 | 
                <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14460.20"/>  | 
            
| 9 | 5 | 
                <capability name="Safe area layout guides" minToolsVersion="9.0"/>  | 
            
| 10 | 6 | 
                <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>  | 
            
                @@ -213,8 +209,8 @@  | 
            ||
| 213 | 209 | 
                <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>  | 
            
| 214 | 210 | 
                <nil key="highlightedColor"/>  | 
            
| 215 | 211 | 
                </label>  | 
            
| 216 | 
                - <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="列表箭头" translatesAutoresizingMaskIntoConstraints="NO" id="mre-Tt-F0S">  | 
            |
| 217 | 
                - <rect key="frame" x="341" y="14" width="24" height="36"/>  | 
            |
| 212 | 
                + <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="list-arrow" translatesAutoresizingMaskIntoConstraints="NO" id="mre-Tt-F0S">  | 
            |
| 213 | 
                + <rect key="frame" x="349" y="24" width="16" height="16"/>  | 
            |
| 218 | 214 | 
                </imageView>  | 
            
| 219 | 215 | 
                <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="T9q-a4-Ugc">  | 
            
| 220 | 216 | 
                <rect key="frame" x="0.0" y="64" width="375" height="64"/>  | 
            
                @@ -230,8 +226,8 @@  | 
            ||
| 230 | 226 | 
                <constraint firstAttribute="width" secondItem="NEm-bF-yno" secondAttribute="height" id="snW-w9-7b3"/>  | 
            
| 231 | 227 | 
                </constraints>  | 
            
| 232 | 228 | 
                </imageView>  | 
            
| 233 | 
                - <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="列表箭头" translatesAutoresizingMaskIntoConstraints="NO" id="8VZ-dR-b6z">  | 
            |
| 234 | 
                - <rect key="frame" x="341" y="78" width="24" height="36"/>  | 
            |
| 229 | 
                + <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="list-arrow" translatesAutoresizingMaskIntoConstraints="NO" id="8VZ-dR-b6z">  | 
            |
| 230 | 
                + <rect key="frame" x="349" y="88" width="16" height="16"/>  | 
            |
| 235 | 231 | 
                </imageView>  | 
            
| 236 | 232 | 
                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="赞" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="J3p-B7-gMi">  | 
            
| 237 | 233 | 
                <rect key="frame" x="70" y="86" width="17" height="20"/>  | 
            
                @@ -253,8 +249,8 @@  | 
            ||
| 253 | 249 | 
                <constraint firstAttribute="width" constant="48" id="Kmf-oj-nfI"/>  | 
            
| 254 | 250 | 
                </constraints>  | 
            
| 255 | 251 | 
                </imageView>  | 
            
| 256 | 
                - <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="列表箭头" translatesAutoresizingMaskIntoConstraints="NO" id="hJe-J2-RpF">  | 
            |
| 257 | 
                - <rect key="frame" x="341" y="142" width="24" height="36"/>  | 
            |
| 252 | 
                + <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="list-arrow" translatesAutoresizingMaskIntoConstraints="NO" id="hJe-J2-RpF">  | 
            |
| 253 | 
                + <rect key="frame" x="349" y="152" width="16" height="16"/>  | 
            |
| 258 | 254 | 
                </imageView>  | 
            
| 259 | 255 | 
                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="评论" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="6fy-0a-WYd">  | 
            
| 260 | 256 | 
                <rect key="frame" x="70" y="150" width="33" height="20"/>  | 
            
                @@ -263,7 +259,7 @@  | 
            ||
| 263 | 259 | 
                <nil key="highlightedColor"/>  | 
            
| 264 | 260 | 
                </label>  | 
            
| 265 | 261 | 
                <view hidden="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="oLf-Xb-QSv">  | 
            
| 266 | 
                - <rect key="frame" x="325" y="28" width="8" height="8"/>  | 
            |
| 262 | 
                + <rect key="frame" x="333" y="28" width="8" height="8"/>  | 
            |
| 267 | 263 | 
                <color key="backgroundColor" red="1" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>  | 
            
| 268 | 264 | 
                <constraints>  | 
            
| 269 | 265 | 
                <constraint firstAttribute="height" constant="8" id="8PB-CF-AvI"/>  | 
            
                @@ -276,7 +272,7 @@  | 
            ||
| 276 | 272 | 
                </userDefinedRuntimeAttributes>  | 
            
| 277 | 273 | 
                </view>  | 
            
| 278 | 274 | 
                <view hidden="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="R8U-gK-x5D">  | 
            
| 279 | 
                - <rect key="frame" x="325" y="92" width="8" height="8"/>  | 
            |
| 275 | 
                + <rect key="frame" x="333" y="92" width="8" height="8"/>  | 
            |
| 280 | 276 | 
                <color key="backgroundColor" red="1" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>  | 
            
| 281 | 277 | 
                <constraints>  | 
            
| 282 | 278 | 
                <constraint firstAttribute="height" constant="8" id="pvk-DY-af3"/>  | 
            
                @@ -289,7 +285,7 @@  | 
            ||
| 289 | 285 | 
                </userDefinedRuntimeAttributes>  | 
            
| 290 | 286 | 
                </view>  | 
            
| 291 | 287 | 
                <view hidden="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Qi9-c7-GCt">  | 
            
| 292 | 
                - <rect key="frame" x="325" y="156" width="8" height="8"/>  | 
            |
| 288 | 
                + <rect key="frame" x="333" y="156" width="8" height="8"/>  | 
            |
| 293 | 289 | 
                <color key="backgroundColor" red="1" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>  | 
            
| 294 | 290 | 
                <constraints>  | 
            
| 295 | 291 | 
                <constraint firstAttribute="height" constant="8" id="d1V-XC-UJk"/>  | 
            
                @@ -390,10 +386,10 @@  | 
            ||
| 390 | 386 | 
                </scene>  | 
            
| 391 | 387 | 
                </scenes>  | 
            
| 392 | 388 | 
                <resources>  | 
            
| 389 | 
                + <image name="list-arrow" width="16" height="16"/>  | 
            |
| 393 | 390 | 
                <image name="message-comment" width="144" height="144"/>  | 
            
| 394 | 391 | 
                <image name="message-system" width="144" height="144"/>  | 
            
| 395 | 392 | 
                <image name="message-thumpub" width="144" height="144"/>  | 
            
| 396 | 
                - <image name="列表箭头" width="24" height="36"/>  | 
            |
| 397 | 393 | 
                <image name="默认头像" width="240" height="240"/>  | 
            
| 398 | 394 | 
                </resources>  | 
            
| 399 | 395 | 
                </document>  | 
            
                @@ -13,11 +13,11 @@ final class MessageCommentAndThumbupCell: UITableViewCell {
               | 
            ||
| 13 | 13 | 
                 | 
            
| 14 | 14 | 
                // MARK: Storyboard property  | 
            
| 15 | 15 | 
                @IBOutlet weak var thumbupOrComment: UILabel!  | 
            
| 16 | 
                - @IBOutlet var userImage: UIImageView!  | 
            |
| 17 | 
                - @IBOutlet var username: UILabel!  | 
            |
| 18 | 
                - @IBOutlet var content: UILabel!  | 
            |
| 19 | 
                - @IBOutlet var time: UILabel!  | 
            |
| 20 | 
                - @IBOutlet var myPhoto: UIImageView!  | 
            |
| 16 | 
                + @IBOutlet weak var userImage: UIImageView!  | 
            |
| 17 | 
                + @IBOutlet weak var username: UILabel!  | 
            |
| 18 | 
                + @IBOutlet weak var content: UILabel!  | 
            |
| 19 | 
                + @IBOutlet weak var time: UILabel!  | 
            |
| 20 | 
                + @IBOutlet weak var myPhoto: UIImageView!  | 
            |
| 21 | 21 | 
                 | 
            
| 22 | 22 | 
                // MARK: view function  | 
            
| 23 | 23 | 
                     override func awakeFromNib() {
               | 
            
                @@ -20,7 +20,7 @@ protocol MessageViewControllerDelegate: class {
               | 
            ||
| 20 | 20 | 
                 | 
            
| 21 | 21 | 
                 final class MessageListViewController: UIViewController {
               | 
            
| 22 | 22 | 
                 | 
            
| 23 | 
                - @IBOutlet var tableView: UITableView!  | 
            |
| 23 | 
                + @IBOutlet weak var tableView: UITableView!  | 
            |
| 24 | 24 | 
                 | 
            
| 25 | 25 | 
                     var emptyView : UILabel = {
               | 
            
| 26 | 26 | 
                let empty = UILabel(frame: CGRect(x: kScreenWidth / 2 - 50, y: 74, width: 50, height: 50))  | 
            
                @@ -19,7 +19,7 @@ final class MessageSystemCell: UITableViewCell {
               | 
            ||
| 19 | 19 | 
                 | 
            
| 20 | 20 | 
                     func setInfo(_ info: MessageListItem) {
               | 
            
| 21 | 21 | 
                // userImage.setImageWithNullableURL(info.url, placeholderImage: defaultAvatar)  | 
            
| 22 | 
                - name.text = info.title  | 
            |
| 22 | 
                + name.text = info.msg_title  | 
            |
| 23 | 23 | 
                content.text = info.content  | 
            
| 24 | 24 | 
                }  | 
            
| 25 | 25 | 
                }  | 
            
                @@ -12,9 +12,9 @@ import PaiaiDataKit  | 
            ||
| 12 | 12 | 
                 | 
            
| 13 | 13 | 
                 class MessageViewController: UIViewController {
               | 
            
| 14 | 14 | 
                 | 
            
| 15 | 
                - @IBOutlet var sysUnreadTip: UIView!  | 
            |
| 16 | 
                - @IBOutlet var thumbupUnreadTip: UIView!  | 
            |
| 17 | 
                - @IBOutlet var commentUnreadTip: UIView!  | 
            |
| 15 | 
                + @IBOutlet weak var sysUnreadTip: UIView!  | 
            |
| 16 | 
                + @IBOutlet weak var thumbupUnreadTip: UIView!  | 
            |
| 17 | 
                + @IBOutlet weak var commentUnreadTip: UIView!  | 
            |
| 18 | 18 | 
                 | 
            
| 19 | 19 | 
                @IBOutlet weak var sysBtn: UIButton!  | 
            
| 20 | 20 | 
                @IBOutlet weak var thumbupBtn: UIButton!  | 
            
                @@ -13,9 +13,9 @@ import PaiaiUIKit  | 
            ||
| 13 | 13 | 
                 final class GroupCell: UITableViewCell {
               | 
            
| 14 | 14 | 
                 | 
            
| 15 | 15 | 
                // MARK: Storyboard property  | 
            
| 16 | 
                - @IBOutlet var groupImageView: UIImageView!  | 
            |
| 17 | 
                - @IBOutlet var groupNameLabel: UILabel!  | 
            |
| 18 | 
                - @IBOutlet var createTimeLabel: UILabel!  | 
            |
| 16 | 
                + @IBOutlet weak var groupImageView: UIImageView!  | 
            |
| 17 | 
                + @IBOutlet weak var groupNameLabel: UILabel!  | 
            |
| 18 | 
                + @IBOutlet weak var createTimeLabel: UILabel!  | 
            |
| 19 | 19 | 
                @IBOutlet weak var photoNumLabel: UILabel!  | 
            
| 20 | 20 | 
                 | 
            
| 21 | 21 | 
                // MARK: init interface  | 
            
                @@ -42,7 +42,7 @@  | 
            ||
| 42 | 42 | 
                </userDefinedRuntimeAttribute>  | 
            
| 43 | 43 | 
                </userDefinedRuntimeAttributes>  | 
            
| 44 | 44 | 
                </imageView>  | 
            
| 45 | 
                - <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="列表箭头" translatesAutoresizingMaskIntoConstraints="NO" id="GAH-5d-ArA">  | 
            |
| 45 | 
                + <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="list-arrow" translatesAutoresizingMaskIntoConstraints="NO" id="GAH-5d-ArA">  | 
            |
| 46 | 46 | 
                <rect key="frame" x="339" y="12" width="24" height="36"/>  | 
            
| 47 | 47 | 
                </imageView>  | 
            
| 48 | 48 | 
                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="群名称" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Bx9-cB-B0U">  | 
            
                @@ -127,23 +127,15 @@  | 
            ||
| 127 | 127 | 
                <fontDescription key="fontDescription" type="system" pointSize="14"/>  | 
            
| 128 | 128 | 
                <textInputTraits key="textInputTraits" autocapitalizationType="sentences"/>  | 
            
| 129 | 129 | 
                </textView>  | 
            
| 130 | 
                - <button opaque="NO" contentMode="scaleToFill" enabled="NO" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="kyg-hG-JSP">  | 
            |
| 130 | 
                + <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="kyg-hG-JSP">  | 
            |
| 131 | 131 | 
                <rect key="frame" x="0.0" y="190" width="375" height="45"/>  | 
            
| 132 | 132 | 
                <constraints>  | 
            
| 133 | 133 | 
                <constraint firstAttribute="height" constant="45" id="x3X-y4-kmZ"/>  | 
            
| 134 | 134 | 
                </constraints>  | 
            
| 135 | 135 | 
                <fontDescription key="fontDescription" type="system" pointSize="20"/>  | 
            
| 136 | 
                - <state key="normal" title="发送">  | 
            |
| 136 | 
                + <state key="normal" title="发送" backgroundImage="BTN-send">  | 
            |
| 137 | 137 | 
                <color key="titleColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>  | 
            
| 138 | 138 | 
                </state>  | 
            
| 139 | 
                - <userDefinedRuntimeAttributes>  | 
            |
| 140 | 
                - <userDefinedRuntimeAttribute type="color" keyPath="normalStatusBackgroundColor">  | 
            |
| 141 | 
                - <color key="value" red="0.98431372549999996" green="0.31372549020000001" blue="0.31372549020000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>  | 
            |
| 142 | 
                - </userDefinedRuntimeAttribute>  | 
            |
| 143 | 
                - <userDefinedRuntimeAttribute type="color" keyPath="pressedStatusBackgroundColor">  | 
            |
| 144 | 
                - <color key="value" red="0.98431372549999996" green="0.31372549020000001" blue="0.31372549020000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>  | 
            |
| 145 | 
                - </userDefinedRuntimeAttribute>  | 
            |
| 146 | 
                - </userDefinedRuntimeAttributes>  | 
            |
| 147 | 139 | 
                <connections>  | 
            
| 148 | 140 | 
                <action selector="sendFeedBack" destination="iwu-HG-AWF" eventType="touchUpInside" id="hQt-ku-2nH"/>  | 
            
| 149 | 141 | 
                </connections>  | 
            
                @@ -228,7 +220,7 @@  | 
            ||
| 228 | 220 | 
                <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>  | 
            
| 229 | 221 | 
                <nil key="highlightedColor"/>  | 
            
| 230 | 222 | 
                </label>  | 
            
| 231 | 
                - <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="列表箭头" translatesAutoresizingMaskIntoConstraints="NO" id="MgR-ta-3jg">  | 
            |
| 223 | 
                + <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="list-arrow" translatesAutoresizingMaskIntoConstraints="NO" id="MgR-ta-3jg">  | 
            |
| 232 | 224 | 
                <rect key="frame" x="349" y="6" width="24" height="36"/>  | 
            
| 233 | 225 | 
                </imageView>  | 
            
| 234 | 226 | 
                <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="L1g-sb-a5F">  | 
            
                @@ -263,7 +255,7 @@  | 
            ||
| 263 | 255 | 
                <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>  | 
            
| 264 | 256 | 
                <nil key="highlightedColor"/>  | 
            
| 265 | 257 | 
                </label>  | 
            
| 266 | 
                - <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="列表箭头" translatesAutoresizingMaskIntoConstraints="NO" id="vLw-Zd-Mis">  | 
            |
| 258 | 
                + <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="list-arrow" translatesAutoresizingMaskIntoConstraints="NO" id="vLw-Zd-Mis">  | 
            |
| 267 | 259 | 
                <rect key="frame" x="349" y="6" width="24" height="36"/>  | 
            
| 268 | 260 | 
                </imageView>  | 
            
| 269 | 261 | 
                <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="FIE-jb-ZGu">  | 
            
                @@ -298,7 +290,7 @@  | 
            ||
| 298 | 290 | 
                <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>  | 
            
| 299 | 291 | 
                <nil key="highlightedColor"/>  | 
            
| 300 | 292 | 
                </label>  | 
            
| 301 | 
                - <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="列表箭头" translatesAutoresizingMaskIntoConstraints="NO" id="mhJ-Uj-tdj">  | 
            |
| 293 | 
                + <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="list-arrow" translatesAutoresizingMaskIntoConstraints="NO" id="mhJ-Uj-tdj">  | 
            |
| 302 | 294 | 
                <rect key="frame" x="349" y="6" width="24" height="36"/>  | 
            
| 303 | 295 | 
                </imageView>  | 
            
| 304 | 296 | 
                <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="VGv-oO-leT">  | 
            
                @@ -623,12 +615,13 @@  | 
            ||
| 623 | 615 | 
                </scene>  | 
            
| 624 | 616 | 
                </scenes>  | 
            
| 625 | 617 | 
                <resources>  | 
            
| 618 | 
                + <image name="BTN-send" width="608" height="304"/>  | 
            |
| 626 | 619 | 
                <image name="Logo" width="140" height="140"/>  | 
            
| 627 | 620 | 
                <image name="about-contactUs" width="32" height="32"/>  | 
            
| 628 | 621 | 
                <image name="about-score" width="32" height="32"/>  | 
            
| 629 | 622 | 
                <image name="about-userAgreement" width="32" height="32"/>  | 
            
| 623 | 
                + <image name="list-arrow" width="24" height="36"/>  | 
            |
| 630 | 624 | 
                <image name="navigation-background" width="12" height="132"/>  | 
            
| 631 | 
                - <image name="列表箭头" width="24" height="36"/>  | 
            |
| 632 | 625 | 
                <image name="注销切图" width="32" height="32"/>  | 
            
| 633 | 626 | 
                <image name="默认头像" width="240" height="240"/>  | 
            
| 634 | 627 | 
                </resources>  | 
            
                @@ -17,7 +17,7 @@ final class MineAboutViewController: UIViewController {
               | 
            ||
| 17 | 17 | 
                @IBOutlet weak var contactUsBtn: UIButton!  | 
            
| 18 | 18 | 
                @IBOutlet weak var scoreBtn: UIButton!  | 
            
| 19 | 19 | 
                @IBOutlet weak var userAgreementBtn: UIButton!  | 
            
| 20 | 
                - @IBOutlet var versionLabel: UILabel!  | 
            |
| 20 | 
                + @IBOutlet weak var versionLabel: UILabel!  | 
            |
| 21 | 21 | 
                 | 
            
| 22 | 22 | 
                private var disposeBag = DisposeBag()  | 
            
| 23 | 23 | 
                 | 
            
                @@ -100,7 +100,6 @@ fileprivate extension MineCoordinator {
               | 
            ||
| 100 | 100 | 
                     func makeGroupViewController(item: GroupItem) -> GroupViewController {
               | 
            
| 101 | 101 | 
                let vc = GroupViewController.instantiate()  | 
            
| 102 | 102 | 
                vc.viewModel = GroupViewModel(groupItem: item)  | 
            
| 103 | 
                - vc.groupItem = item  | 
            |
| 104 | 103 | 
                return vc  | 
            
| 105 | 104 | 
                }  | 
            
| 106 | 105 | 
                }  | 
            
                @@ -15,8 +15,8 @@ import PaiaiUIKit  | 
            ||
| 15 | 15 | 
                 final class MineFeedbackViewController: UIViewController {
               | 
            
| 16 | 16 | 
                 | 
            
| 17 | 17 | 
                // MARK: Storyboard property  | 
            
| 18 | 
                - @IBOutlet var textView: UITextView!  | 
            |
| 19 | 
                - @IBOutlet var sendBtn: UIButton!  | 
            |
| 18 | 
                + @IBOutlet weak var textView: UITextView!  | 
            |
| 19 | 
                + @IBOutlet weak var sendBtn: UIButton!  | 
            |
| 20 | 20 | 
                fileprivate let disposeBag = DisposeBag()  | 
            
| 21 | 21 | 
                 | 
            
| 22 | 22 | 
                var feedbackAPI: FeedbackRemoteAPI!  | 
            
                @@ -17,7 +17,7 @@ import PullToRefresh  | 
            ||
| 17 | 17 | 
                 final class MineGroupViewController: UIViewController {
               | 
            
| 18 | 18 | 
                 | 
            
| 19 | 19 | 
                // MARK: Storyboard property  | 
            
| 20 | 
                - @IBOutlet var tableView: UITableView!  | 
            |
| 20 | 
                + @IBOutlet weak var tableView: UITableView!  | 
            |
| 21 | 21 | 
                 | 
            
| 22 | 22 | 
                // MARK: data property  | 
            
| 23 | 23 | 
                fileprivate let disposeBag = DisposeBag()  | 
            
                @@ -17,7 +17,7 @@ import PullToRefresh  | 
            ||
| 17 | 17 | 
                 final class MineOrderViewController: UIViewController {
               | 
            
| 18 | 18 | 
                 | 
            
| 19 | 19 | 
                // MARK: Storyboard property  | 
            
| 20 | 
                - @IBOutlet var tableView: UITableView!  | 
            |
| 20 | 
                + @IBOutlet weak var tableView: UITableView!  | 
            |
| 21 | 21 | 
                 | 
            
| 22 | 22 | 
                // MARK: data property  | 
            
| 23 | 23 | 
                fileprivate let disposeBag = DisposeBag()  | 
            
                @@ -13,10 +13,10 @@ import PaiaiUIKit  | 
            ||
| 13 | 13 | 
                 final class OrderCell: UITableViewCell {
               | 
            
| 14 | 14 | 
                 | 
            
| 15 | 15 | 
                // MARK: Storyboard property  | 
            
| 16 | 
                - @IBOutlet var photo: UIImageView!  | 
            |
| 17 | 
                - @IBOutlet var time: UILabel!  | 
            |
| 18 | 
                - @IBOutlet var price: UILabel!  | 
            |
| 19 | 
                - @IBOutlet var orderNumber: UILabel!  | 
            |
| 16 | 
                + @IBOutlet weak var photo: UIImageView!  | 
            |
| 17 | 
                + @IBOutlet weak var time: UILabel!  | 
            |
| 18 | 
                + @IBOutlet weak var price: UILabel!  | 
            |
| 19 | 
                + @IBOutlet weak var orderNumber: UILabel!  | 
            |
| 20 | 20 | 
                 | 
            
| 21 | 21 | 
                // MARK: init interface  | 
            
| 22 | 22 | 
                     func setInfo(_ info: OrderItem) {
               | 
            
                @@ -11,26 +11,20 @@ import PaiaiDataKit  | 
            ||
| 11 | 11 | 
                import PaiaiUIKit  | 
            
| 12 | 12 | 
                 | 
            
| 13 | 13 | 
                 final class ImageCell: UICollectionViewCell, UIScrollViewDelegate {
               | 
            
| 14 | 
                - @IBOutlet var scrollView: UIScrollView!  | 
            |
| 14 | 
                + @IBOutlet weak var scrollView: UIScrollView!  | 
            |
| 15 | 15 | 
                var photoImage = UIImageView()  | 
            
| 16 | 16 | 
                 | 
            
| 17 | 17 | 
                     func setModel(url: String) {
               | 
            
| 18 | 
                - photoImage.frame = CGRect.init(x: 0, y: 0, width: width, height: height)  | 
            |
| 18 | 
                + photoImage.frame = CGRect(x: 0, y: 0, width: width, height: height)  | 
            |
| 19 | 19 | 
                photoImage.contentMode = .scaleAspectFit  | 
            
| 20 | 20 | 
                scrollView.contentSize = size  | 
            
| 21 | 21 | 
                scrollView.addSubview(photoImage)  | 
            
| 22 | 
                -// photoImage.image = UIImage.imageWithColor(UIColor.black)  | 
            |
| 23 | 
                -        if !url.isEmpty {
               | 
            |
| 24 | 
                -// photoImage.setImageWithNullableURL(url, placeholderImage: UIImage(named: "详情页占位图"))  | 
            |
| 25 | 
                -        } else {
               | 
            |
| 26 | 
                - photoImage.image = UIImage(named: url)  | 
            |
| 27 | 
                - }  | 
            |
| 22 | 
                +  | 
            |
| 23 | 
                + photoImage.setImage(url, placeholder: UIImage.photoPlaceholder)  | 
            |
| 28 | 24 | 
                 | 
            
| 29 | 25 | 
                let tapGr = UITapGestureRecognizer(target: self, action: #selector(ImageCell.doubleTap(_:)))  | 
            
| 30 | 26 | 
                tapGr.numberOfTapsRequired = 2  | 
            
| 31 | 27 | 
                scrollView.addGestureRecognizer(tapGr)  | 
            
| 32 | 
                -  | 
            |
| 33 | 
                -// printLog(scrollView)  | 
            |
| 34 | 28 | 
                }  | 
            
| 35 | 29 | 
                 | 
            
| 36 | 30 | 
                     func viewForZooming(in scrollView: UIScrollView) -> UIView? {
               | 
            
                @@ -43,7 +37,6 @@ final class ImageCell: UICollectionViewCell, UIScrollViewDelegate {
               | 
            ||
| 43 | 37 | 
                         } else {
               | 
            
| 44 | 38 | 
                //Zoom to rect  | 
            
| 45 | 39 | 
                let tapPt = gr.location(in: scrollView)  | 
            
| 46 | 
                -// printLog(tapPt)  | 
            |
| 47 | 40 | 
                var zoomRect = CGRect.zero  | 
            
| 48 | 41 | 
                zoomRect.size.width = frame.width / scrollView.maximumZoomScale  | 
            
| 49 | 42 | 
                zoomRect.size.height = frame.height / scrollView.maximumZoomScale  | 
            
                @@ -1,445 +1,300 @@  | 
            ||
| 1 | 1 | 
                <?xml version="1.0" encoding="UTF-8"?>  | 
            
| 2 | 
                -<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14460.31" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" colorMatched="YES" initialViewController="qsT-Pc-Bhh">  | 
            |
| 2 | 
                +<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14460.31" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useSafeAreas="YES" colorMatched="YES">  | 
            |
| 3 | 
                + <device id="retina4_7" orientation="portrait">  | 
            |
| 4 | 
                + <adaptation id="fullscreen"/>  | 
            |
| 5 | 
                + </device>  | 
            |
| 3 | 6 | 
                <dependencies>  | 
            
| 7 | 
                + <deployment identifier="iOS"/>  | 
            |
| 4 | 8 | 
                <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14460.20"/>  | 
            
| 9 | 
                + <capability name="Safe area layout guides" minToolsVersion="9.0"/>  | 
            |
| 5 | 10 | 
                <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>  | 
            
| 6 | 11 | 
                </dependencies>  | 
            
| 7 | 12 | 
                <scenes>  | 
            
| 8 | 
                - <!--ReportController-->  | 
            |
| 9 | 
                - <scene sceneID="wUV-hi-YAV">  | 
            |
| 10 | 
                - <objects>  | 
            |
| 11 | 
                - <viewController storyboardIdentifier="ReportController" automaticallyAdjustsScrollViewInsets="NO" id="DkF-mX-lIk" userLabel="ReportController" customClass="ReportController" customModule="Paiai_iOS" customModuleProvider="target" sceneMemberID="viewController">  | 
            |
| 12 | 
                - <layoutGuides>  | 
            |
| 13 | 
                - <viewControllerLayoutGuide type="top" id="4jJ-Gj-1F2"/>  | 
            |
| 14 | 
                - <viewControllerLayoutGuide type="bottom" id="ZhS-9D-uxH"/>  | 
            |
| 15 | 
                - </layoutGuides>  | 
            |
| 16 | 
                - <view key="view" contentMode="scaleToFill" id="VKJ-Rl-cDh">  | 
            |
| 17 | 
                - <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>  | 
            |
| 18 | 
                - <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>  | 
            |
| 19 | 
                - <subviews>  | 
            |
| 20 | 
                - <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="dKK-5n-7NI">  | 
            |
| 21 | 
                - <rect key="frame" x="0.0" y="467" width="375" height="200"/>  | 
            |
| 22 | 
                - <subviews>  | 
            |
| 23 | 
                - <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="r4F-Uk-4U9">  | 
            |
| 24 | 
                - <rect key="frame" x="0.0" y="152" width="375" height="48"/>  | 
            |
| 25 | 
                - <constraints>  | 
            |
| 26 | 
                - <constraint firstAttribute="height" constant="48" id="PNZ-IF-PSp"/>  | 
            |
| 27 | 
                - </constraints>  | 
            |
| 28 | 
                - <fontDescription key="fontDescription" type="system" pointSize="20"/>  | 
            |
| 29 | 
                - <state key="normal" title="取消">  | 
            |
| 30 | 
                - <color key="titleColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>  | 
            |
| 31 | 
                - </state>  | 
            |
| 32 | 
                - <connections>  | 
            |
| 33 | 
                - <action selector="cancelAction:" destination="DkF-mX-lIk" eventType="touchUpInside" id="bXf-2r-PWF"/>  | 
            |
| 34 | 
                - </connections>  | 
            |
| 35 | 
                - </button>  | 
            |
| 36 | 
                - <tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="44" sectionHeaderHeight="28" sectionFooterHeight="28" translatesAutoresizingMaskIntoConstraints="NO" id="hrt-tA-trR">  | 
            |
| 37 | 
                - <rect key="frame" x="0.0" y="0.0" width="375" height="152"/>  | 
            |
| 38 | 
                - <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>  | 
            |
| 39 | 
                - <prototypes>  | 
            |
| 40 | 
                - <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" reuseIdentifier="reportCell" id="mem-R8-etc">  | 
            |
| 41 | 
                - <rect key="frame" x="0.0" y="28" width="375" height="44"/>  | 
            |
| 42 | 
                - <autoresizingMask key="autoresizingMask"/>  | 
            |
| 43 | 
                - <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="mem-R8-etc" id="tpv-xM-lZp">  | 
            |
| 44 | 
                - <rect key="frame" x="0.0" y="0.0" width="375" height="43.5"/>  | 
            |
| 45 | 
                - <autoresizingMask key="autoresizingMask"/>  | 
            |
| 46 | 
                - </tableViewCellContentView>  | 
            |
| 47 | 
                - </tableViewCell>  | 
            |
| 48 | 
                - </prototypes>  | 
            |
| 49 | 
                - <connections>  | 
            |
| 50 | 
                - <outlet property="dataSource" destination="DkF-mX-lIk" id="NNr-XE-WFH"/>  | 
            |
| 51 | 
                - <outlet property="delegate" destination="DkF-mX-lIk" id="Ar9-vT-UJr"/>  | 
            |
| 52 | 
                - </connections>  | 
            |
| 53 | 
                - </tableView>  | 
            |
| 54 | 
                - </subviews>  | 
            |
| 55 | 
                - <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>  | 
            |
| 56 | 
                - <constraints>  | 
            |
| 57 | 
                - <constraint firstAttribute="trailing" secondItem="r4F-Uk-4U9" secondAttribute="trailing" id="QiQ-0q-XK9"/>  | 
            |
| 58 | 
                - <constraint firstAttribute="bottom" secondItem="r4F-Uk-4U9" secondAttribute="bottom" id="TWR-hL-NWZ"/>  | 
            |
| 59 | 
                - <constraint firstItem="r4F-Uk-4U9" firstAttribute="leading" secondItem="dKK-5n-7NI" secondAttribute="leading" id="XkS-7p-opA"/>  | 
            |
| 60 | 
                - <constraint firstItem="r4F-Uk-4U9" firstAttribute="top" secondItem="hrt-tA-trR" secondAttribute="bottom" id="haU-qN-JV2"/>  | 
            |
| 61 | 
                - <constraint firstItem="hrt-tA-trR" firstAttribute="leading" secondItem="dKK-5n-7NI" secondAttribute="leading" id="loV-jI-jzd"/>  | 
            |
| 62 | 
                - <constraint firstAttribute="height" constant="200" id="m2O-Lg-r1R"/>  | 
            |
| 63 | 
                - <constraint firstItem="hrt-tA-trR" firstAttribute="top" secondItem="dKK-5n-7NI" secondAttribute="top" id="rtt-WL-c3Z"/>  | 
            |
| 64 | 
                - <constraint firstAttribute="trailing" secondItem="hrt-tA-trR" secondAttribute="trailing" id="wVv-Cc-7Ox"/>  | 
            |
| 65 | 
                - </constraints>  | 
            |
| 66 | 
                - </view>  | 
            |
| 67 | 
                - </subviews>  | 
            |
| 68 | 
                - <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="calibratedRGB"/>  | 
            |
| 69 | 
                - <constraints>  | 
            |
| 70 | 
                - <constraint firstItem="ZhS-9D-uxH" firstAttribute="top" secondItem="dKK-5n-7NI" secondAttribute="bottom" id="8px-JV-5Rs"/>  | 
            |
| 71 | 
                - <constraint firstItem="dKK-5n-7NI" firstAttribute="leading" secondItem="VKJ-Rl-cDh" secondAttribute="leading" id="Vsd-a3-Kp9"/>  | 
            |
| 72 | 
                - <constraint firstAttribute="trailing" secondItem="dKK-5n-7NI" secondAttribute="trailing" id="pCe-x1-6IP"/>  | 
            |
| 73 | 
                - </constraints>  | 
            |
| 74 | 
                - </view>  | 
            |
| 75 | 
                - <connections>  | 
            |
| 76 | 
                - <outlet property="contentView" destination="dKK-5n-7NI" id="I15-oP-aR3"/>  | 
            |
| 77 | 
                - <outlet property="reportTableView" destination="hrt-tA-trR" id="gkP-cc-Emj"/>  | 
            |
| 78 | 
                - </connections>  | 
            |
| 79 | 
                - </viewController>  | 
            |
| 80 | 
                - <placeholder placeholderIdentifier="IBFirstResponder" id="FMr-bp-t1r" userLabel="First Responder" sceneMemberID="firstResponder"/>  | 
            |
| 81 | 
                - </objects>  | 
            |
| 82 | 
                - <point key="canvasLocation" x="-953.60000000000002" y="1390.704647676162"/>  | 
            |
| 83 | 
                - </scene>  | 
            |
| 84 | 13 | 
                <!--PhotoDetailViewController-->  | 
            
| 85 | 14 | 
                <scene sceneID="OIh-Ut-mfb">  | 
            
| 86 | 15 | 
                <objects>  | 
            
| 87 | 
                - <viewController storyboardIdentifier="PhotoDetailViewController" automaticallyAdjustsScrollViewInsets="NO" id="qsT-Pc-Bhh" userLabel="PhotoDetailViewController" customClass="PhotoDetailViewController" customModule="PaiAi" sceneMemberID="viewController">  | 
            |
| 88 | 
                - <layoutGuides>  | 
            |
| 89 | 
                - <viewControllerLayoutGuide type="top" id="aUY-hC-XIK"/>  | 
            |
| 90 | 
                - <viewControllerLayoutGuide type="bottom" id="9RM-c8-CL6"/>  | 
            |
| 91 | 
                - </layoutGuides>  | 
            |
| 16 | 
                + <viewController storyboardIdentifier="PhotoDetailViewController" automaticallyAdjustsScrollViewInsets="NO" id="qsT-Pc-Bhh" userLabel="PhotoDetailViewController" customClass="PhotoDetailViewController" customModule="Paiai_iOS" customModuleProvider="target" sceneMemberID="viewController">  | 
            |
| 92 | 17 | 
                <view key="view" contentMode="scaleToFill" id="DXj-L8-o9b">  | 
            
| 93 | 
                - <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>  | 
            |
| 18 | 
                + <rect key="frame" x="0.0" y="0.0" width="375" height="1000"/>  | 
            |
| 94 | 19 | 
                <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>  | 
            
| 95 | 20 | 
                <subviews>  | 
            
| 96 | 
                - <tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" showsHorizontalScrollIndicator="NO" showsVerticalScrollIndicator="NO" dataMode="prototypes" style="plain" allowsSelection="NO" rowHeight="409" sectionHeaderHeight="28" sectionFooterHeight="28" translatesAutoresizingMaskIntoConstraints="NO" id="BJb-h6-o9s">  | 
            |
| 97 | 
                - <rect key="frame" x="0.0" y="20" width="375" height="647"/>  | 
            |
| 98 | 
                - <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>  | 
            |
| 99 | 
                - <color key="separatorColor" red="0.94117647058823528" green="0.94117647058823528" blue="0.94117647058823528" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>  | 
            |
| 100 | 
                - <prototypes>  | 
            |
| 101 | 
                - <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" reuseIdentifier="headCell" rowHeight="48" id="i3U-Ls-3d4" customClass="DetailPageHeadCell" customModule="Paiai_iOS" customModuleProvider="target">  | 
            |
| 102 | 
                - <rect key="frame" x="0.0" y="28" width="375" height="48"/>  | 
            |
| 103 | 
                - <autoresizingMask key="autoresizingMask"/>  | 
            |
| 104 | 
                - <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="i3U-Ls-3d4" id="wrX-0i-fve">  | 
            |
| 105 | 
                - <rect key="frame" x="0.0" y="0.0" width="375" height="47.5"/>  | 
            |
| 106 | 
                - <autoresizingMask key="autoresizingMask"/>  | 
            |
| 21 | 
                + <tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" translatesAutoresizingMaskIntoConstraints="NO" id="fD2-Ow-gtt">  | 
            |
| 22 | 
                + <rect key="frame" x="0.0" y="20" width="375" height="980"/>  | 
            |
| 23 | 
                + <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>  | 
            |
| 24 | 
                + <view key="tableHeaderView" contentMode="scaleToFill" id="kJj-s4-SK1" userLabel="header view">  | 
            |
| 25 | 
                + <rect key="frame" x="0.0" y="0.0" width="375" height="533"/>  | 
            |
| 26 | 
                + <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>  | 
            |
| 27 | 
                + <subviews>  | 
            |
| 28 | 
                + <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="rL2-VZ-0O7" userLabel="Group Info View">  | 
            |
| 29 | 
                + <rect key="frame" x="0.0" y="0.0" width="375" height="48"/>  | 
            |
| 107 | 30 | 
                <subviews>  | 
            
| 108 | 
                - <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="mcz-eC-zz1">  | 
            |
| 109 | 
                - <rect key="frame" x="0.0" y="0.0" width="375" height="47.5"/>  | 
            |
| 31 | 
                + <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="nng-M9-7cj">  | 
            |
| 32 | 
                + <rect key="frame" x="10" y="10" width="28" height="28"/>  | 
            |
| 33 | 
                + <constraints>  | 
            |
| 34 | 
                + <constraint firstAttribute="width" secondItem="nng-M9-7cj" secondAttribute="height" id="69G-dm-HcL"/>  | 
            |
| 35 | 
                + <constraint firstAttribute="width" constant="28" id="Pq9-h7-Ls2"/>  | 
            |
| 36 | 
                + </constraints>  | 
            |
| 37 | 
                + <userDefinedRuntimeAttributes>  | 
            |
| 38 | 
                + <userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">  | 
            |
| 39 | 
                + <real key="value" value="14"/>  | 
            |
| 40 | 
                + </userDefinedRuntimeAttribute>  | 
            |
| 41 | 
                + <userDefinedRuntimeAttribute type="number" keyPath="borderWidth">  | 
            |
| 42 | 
                + <real key="value" value="0.5"/>  | 
            |
| 43 | 
                + </userDefinedRuntimeAttribute>  | 
            |
| 44 | 
                + <userDefinedRuntimeAttribute type="color" keyPath="borderColor">  | 
            |
| 45 | 
                + <color key="value" white="0.66666666669999997" alpha="1" colorSpace="calibratedWhite"/>  | 
            |
| 46 | 
                + </userDefinedRuntimeAttribute>  | 
            |
| 47 | 
                + </userDefinedRuntimeAttributes>  | 
            |
| 48 | 
                + </imageView>  | 
            |
| 49 | 
                + <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="群名称" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="XM7-FX-tOk">  | 
            |
| 50 | 
                + <rect key="frame" x="48" y="15.5" width="43" height="17"/>  | 
            |
| 51 | 
                + <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>  | 
            |
| 52 | 
                + <fontDescription key="fontDescription" type="system" pointSize="14"/>  | 
            |
| 53 | 
                + <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>  | 
            |
| 54 | 
                + <nil key="highlightedColor"/>  | 
            |
| 55 | 
                + </label>  | 
            |
| 56 | 
                + <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="gSr-Cm-y1W">  | 
            |
| 57 | 
                + <rect key="frame" x="300" y="0.0" width="75" height="48"/>  | 
            |
| 110 | 58 | 
                <subviews>  | 
            
| 111 | 
                - <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="Qun-83-nZU">  | 
            |
| 112 | 
                - <rect key="frame" x="10" y="10" width="28" height="28"/>  | 
            |
| 113 | 
                - <constraints>  | 
            |
| 114 | 
                - <constraint firstAttribute="width" secondItem="Qun-83-nZU" secondAttribute="height" id="faj-ic-igd"/>  | 
            |
| 115 | 
                - <constraint firstAttribute="width" constant="28" id="lVF-LX-TCT"/>  | 
            |
| 116 | 
                - </constraints>  | 
            |
| 117 | 
                - <userDefinedRuntimeAttributes>  | 
            |
| 118 | 
                - <userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">  | 
            |
| 119 | 
                - <real key="value" value="14"/>  | 
            |
| 120 | 
                - </userDefinedRuntimeAttribute>  | 
            |
| 121 | 
                - <userDefinedRuntimeAttribute type="number" keyPath="borderWidth">  | 
            |
| 122 | 
                - <real key="value" value="0.5"/>  | 
            |
| 123 | 
                - </userDefinedRuntimeAttribute>  | 
            |
| 124 | 
                - <userDefinedRuntimeAttribute type="color" keyPath="borderColor">  | 
            |
| 125 | 
                - <color key="value" white="0.66666666666666663" alpha="1" colorSpace="calibratedWhite"/>  | 
            |
| 126 | 
                - </userDefinedRuntimeAttribute>  | 
            |
| 127 | 
                - </userDefinedRuntimeAttributes>  | 
            |
| 128 | 
                - </imageView>  | 
            |
| 129 | 
                - <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="群名称" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="PYj-cS-z4N">  | 
            |
| 130 | 
                - <rect key="frame" x="48" y="15.5" width="43" height="17"/>  | 
            |
| 59 | 
                + <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="进入群" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="VBE-46-KXK">  | 
            |
| 60 | 
                + <rect key="frame" x="19" y="18" width="31" height="12"/>  | 
            |
| 131 | 61 | 
                <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>  | 
            
| 132 | 
                - <fontDescription key="fontDescription" type="system" pointSize="14"/>  | 
            |
| 133 | 
                - <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>  | 
            |
| 62 | 
                + <fontDescription key="fontDescription" type="system" pointSize="10"/>  | 
            |
| 63 | 
                + <color key="textColor" red="0.98431372549999996" green="0.31372549020000001" blue="0.31372549020000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>  | 
            |
| 134 | 64 | 
                <nil key="highlightedColor"/>  | 
            
| 135 | 65 | 
                </label>  | 
            
| 136 | 
                - <button opaque="NO" tag="40001" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="1wY-9u-hwn">  | 
            |
| 137 | 
                - <rect key="frame" x="243" y="11" width="60" height="25"/>  | 
            |
| 138 | 
                - <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>  | 
            |
| 139 | 
                - <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="calibratedRGB"/>  | 
            |
| 140 | 
                - <state key="normal" title="举报"/>  | 
            |
| 141 | 
                - </button>  | 
            |
| 142 | 
                - <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="vNs-t5-E73">  | 
            |
| 143 | 
                - <rect key="frame" x="300" y="0.0" width="75" height="47.5"/>  | 
            |
| 144 | 
                - <subviews>  | 
            |
| 145 | 
                - <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="E7A-3b-Oup">  | 
            |
| 146 | 
                - <rect key="frame" x="0.0" y="0.0" width="75" height="47.5"/>  | 
            |
| 147 | 
                - <connections>  | 
            |
| 148 | 
                - <action selector="enterGroup" destination="i3U-Ls-3d4" eventType="touchUpInside" id="u7N-vm-SPZ"/>  | 
            |
| 149 | 
                - </connections>  | 
            |
| 150 | 
                - </button>  | 
            |
| 151 | 
                - <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="进入群" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="KGW-c8-vqa">  | 
            |
| 152 | 
                - <rect key="frame" x="19" y="18" width="31" height="12"/>  | 
            |
| 153 | 
                - <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>  | 
            |
| 154 | 
                - <fontDescription key="fontDescription" type="system" pointSize="10"/>  | 
            |
| 155 | 
                - <color key="textColor" red="0.98431372549999996" green="0.31372549020000001" blue="0.31372549020000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>  | 
            |
| 156 | 
                - <nil key="highlightedColor"/>  | 
            |
| 157 | 
                - </label>  | 
            |
| 158 | 
                - <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="进入群" translatesAutoresizingMaskIntoConstraints="NO" id="dhi-7u-NYu">  | 
            |
| 159 | 
                - <rect key="frame" x="9" y="11.5" width="60" height="25"/>  | 
            |
| 160 | 
                - <constraints>  | 
            |
| 161 | 
                - <constraint firstAttribute="height" constant="25" id="dTO-tb-zE5"/>  | 
            |
| 162 | 
                - <constraint firstAttribute="width" constant="60" id="mIF-dz-pKG"/>  | 
            |
| 163 | 
                - </constraints>  | 
            |
| 164 | 
                - </imageView>  | 
            |
| 165 | 
                - </subviews>  | 
            |
| 166 | 
                - <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>  | 
            |
| 66 | 
                + <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="进入群" translatesAutoresizingMaskIntoConstraints="NO" id="70o-zv-I0l">  | 
            |
| 67 | 
                + <rect key="frame" x="9" y="11.5" width="60" height="25"/>  | 
            |
| 167 | 68 | 
                <constraints>  | 
            
| 168 | 
                - <constraint firstAttribute="trailing" secondItem="KGW-c8-vqa" secondAttribute="trailing" constant="25" id="0dn-xR-eOs"/>  | 
            |
| 169 | 
                - <constraint firstAttribute="trailing" secondItem="dhi-7u-NYu" secondAttribute="trailing" constant="6" id="36c-1S-xFf"/>  | 
            |
| 170 | 
                - <constraint firstItem="E7A-3b-Oup" firstAttribute="top" secondItem="vNs-t5-E73" secondAttribute="top" id="GK3-PV-8bY"/>  | 
            |
| 171 | 
                - <constraint firstAttribute="trailing" secondItem="E7A-3b-Oup" secondAttribute="trailing" id="KSp-sT-kJX"/>  | 
            |
| 172 | 
                - <constraint firstAttribute="width" constant="75" id="TRt-Gp-4pZ"/>  | 
            |
| 173 | 
                - <constraint firstAttribute="bottom" secondItem="E7A-3b-Oup" secondAttribute="bottom" id="XJv-kC-HNg"/>  | 
            |
| 174 | 
                - <constraint firstItem="KGW-c8-vqa" firstAttribute="centerY" secondItem="vNs-t5-E73" secondAttribute="centerY" id="gzf-lb-UQR"/>  | 
            |
| 175 | 
                - <constraint firstItem="dhi-7u-NYu" firstAttribute="centerY" secondItem="vNs-t5-E73" secondAttribute="centerY" id="oVV-L7-SwG"/>  | 
            |
| 176 | 
                - <constraint firstItem="E7A-3b-Oup" firstAttribute="leading" secondItem="vNs-t5-E73" secondAttribute="leading" id="z56-tc-xs8"/>  | 
            |
| 69 | 
                + <constraint firstAttribute="height" constant="25" id="X8l-P5-3Rd"/>  | 
            |
| 70 | 
                + <constraint firstAttribute="width" constant="60" id="hNf-F0-tvW"/>  | 
            |
| 177 | 71 | 
                </constraints>  | 
            
| 178 | 
                - </view>  | 
            |
| 72 | 
                + </imageView>  | 
            |
| 179 | 73 | 
                </subviews>  | 
            
| 180 | 
                - <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>  | 
            |
| 74 | 
                + <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>  | 
            |
| 181 | 75 | 
                <constraints>  | 
            
| 182 | 
                - <constraint firstItem="Qun-83-nZU" firstAttribute="leading" secondItem="mcz-eC-zz1" secondAttribute="leading" constant="10" id="4Uk-DP-TXV"/>  | 
            |
| 183 | 
                - <constraint firstItem="PYj-cS-z4N" firstAttribute="leading" secondItem="Qun-83-nZU" secondAttribute="trailing" constant="10" id="4iY-yd-PZA"/>  | 
            |
| 184 | 
                - <constraint firstAttribute="trailing" secondItem="vNs-t5-E73" secondAttribute="trailing" id="VSQ-UO-9pM"/>  | 
            |
| 185 | 
                - <constraint firstItem="vNs-t5-E73" firstAttribute="top" secondItem="mcz-eC-zz1" secondAttribute="top" id="lDC-67-VeA"/>  | 
            |
| 186 | 
                - <constraint firstAttribute="bottom" secondItem="vNs-t5-E73" secondAttribute="bottom" id="m3i-3L-tTn"/>  | 
            |
| 187 | 
                - <constraint firstItem="Qun-83-nZU" firstAttribute="centerY" secondItem="mcz-eC-zz1" secondAttribute="centerY" id="vUx-nv-jbb"/>  | 
            |
| 188 | 
                - <constraint firstItem="PYj-cS-z4N" firstAttribute="centerY" secondItem="Qun-83-nZU" secondAttribute="centerY" id="vco-EW-1A0"/>  | 
            |
| 76 | 
                + <constraint firstAttribute="width" constant="75" id="BPB-Pz-Ugv"/>  | 
            |
| 77 | 
                + <constraint firstItem="70o-zv-I0l" firstAttribute="centerY" secondItem="gSr-Cm-y1W" secondAttribute="centerY" id="ByJ-1c-nyQ"/>  | 
            |
| 78 | 
                + <constraint firstItem="VBE-46-KXK" firstAttribute="centerY" secondItem="gSr-Cm-y1W" secondAttribute="centerY" id="bzl-Og-LB3"/>  | 
            |
| 79 | 
                + <constraint firstAttribute="trailing" secondItem="70o-zv-I0l" secondAttribute="trailing" constant="6" id="cio-Sc-fn0"/>  | 
            |
| 80 | 
                + <constraint firstAttribute="trailing" secondItem="VBE-46-KXK" secondAttribute="trailing" constant="25" id="weN-fs-GNd"/>  | 
            |
| 189 | 81 | 
                </constraints>  | 
            
| 82 | 
                + <connections>  | 
            |
| 83 | 
                + <outletCollection property="gestureRecognizers" destination="EHE-XX-kIE" appends="YES" id="80J-8y-IJs"/>  | 
            |
| 84 | 
                + </connections>  | 
            |
| 190 | 85 | 
                </view>  | 
            
| 191 | 86 | 
                </subviews>  | 
            
| 87 | 
                + <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>  | 
            |
| 192 | 88 | 
                <constraints>  | 
            
| 193 | 
                - <constraint firstItem="mcz-eC-zz1" firstAttribute="leading" secondItem="wrX-0i-fve" secondAttribute="leading" id="6eI-bf-ijz"/>  | 
            |
| 194 | 
                - <constraint firstAttribute="trailing" secondItem="mcz-eC-zz1" secondAttribute="trailing" id="FHX-FY-vOl"/>  | 
            |
| 195 | 
                - <constraint firstAttribute="bottom" secondItem="mcz-eC-zz1" secondAttribute="bottom" id="kkV-lT-uZs"/>  | 
            |
| 196 | 
                - <constraint firstItem="mcz-eC-zz1" firstAttribute="top" secondItem="wrX-0i-fve" secondAttribute="top" id="tWa-Ve-Mgf"/>  | 
            |
| 89 | 
                + <constraint firstAttribute="trailing" secondItem="gSr-Cm-y1W" secondAttribute="trailing" id="5tR-Qu-wtQ"/>  | 
            |
| 90 | 
                + <constraint firstAttribute="bottom" secondItem="gSr-Cm-y1W" secondAttribute="bottom" id="NCO-KD-pVQ"/>  | 
            |
| 91 | 
                + <constraint firstItem="XM7-FX-tOk" firstAttribute="leading" secondItem="nng-M9-7cj" secondAttribute="trailing" constant="10" id="Wig-8j-STm"/>  | 
            |
| 92 | 
                + <constraint firstItem="nng-M9-7cj" firstAttribute="leading" secondItem="rL2-VZ-0O7" secondAttribute="leading" constant="10" id="ZHc-Mw-2tJ"/>  | 
            |
| 93 | 
                + <constraint firstItem="gSr-Cm-y1W" firstAttribute="top" secondItem="rL2-VZ-0O7" secondAttribute="top" id="b1T-Xy-yZs"/>  | 
            |
| 94 | 
                + <constraint firstItem="XM7-FX-tOk" firstAttribute="centerY" secondItem="nng-M9-7cj" secondAttribute="centerY" id="dVs-1n-mqL"/>  | 
            |
| 95 | 
                + <constraint firstAttribute="height" constant="48" id="v42-oR-6qs"/>  | 
            |
| 96 | 
                + <constraint firstItem="nng-M9-7cj" firstAttribute="centerY" secondItem="rL2-VZ-0O7" secondAttribute="centerY" id="zGd-66-ngX"/>  | 
            |
| 197 | 97 | 
                </constraints>  | 
            
| 198 | 
                - </tableViewCellContentView>  | 
            |
| 199 | 
                - <connections>  | 
            |
| 200 | 
                - <outlet property="enterView" destination="vNs-t5-E73" id="wuj-yg-uj8"/>  | 
            |
| 201 | 
                - <outlet property="groupImage" destination="Qun-83-nZU" id="vVq-cH-ZgN"/>  | 
            |
| 202 | 
                - <outlet property="groupName" destination="PYj-cS-z4N" id="RdJ-r6-Jqw"/>  | 
            |
| 203 | 
                - </connections>  | 
            |
| 204 | 
                - </tableViewCell>  | 
            |
| 205 | 
                - <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" reuseIdentifier="detailPagePhotoCell" rowHeight="360" id="5X4-7Q-chL" customClass="DetailPagePhotoCell" customModule="Paiai_iOS" customModuleProvider="target">  | 
            |
| 206 | 
                - <rect key="frame" x="0.0" y="76" width="375" height="360"/>  | 
            |
| 207 | 
                - <autoresizingMask key="autoresizingMask"/>  | 
            |
| 208 | 
                - <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="5X4-7Q-chL" id="yVY-TK-vg7">  | 
            |
| 209 | 
                - <rect key="frame" x="0.0" y="0.0" width="375" height="359.5"/>  | 
            |
| 210 | 
                - <autoresizingMask key="autoresizingMask"/>  | 
            |
| 211 | 
                - <subviews>  | 
            |
| 212 | 
                - <collectionView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" dataMode="prototypes" translatesAutoresizingMaskIntoConstraints="NO" id="lAD-oZ-Zgp">  | 
            |
| 213 | 
                - <rect key="frame" x="0.0" y="0.0" width="375" height="359.5"/>  | 
            |
| 214 | 
                - <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>  | 
            |
| 215 | 
                - <collectionViewFlowLayout key="collectionViewLayout" minimumLineSpacing="10" minimumInteritemSpacing="10" id="A4Q-fW-D0V">  | 
            |
| 216 | 
                - <size key="itemSize" width="375" height="319"/>  | 
            |
| 217 | 
                - <size key="headerReferenceSize" width="0.0" height="0.0"/>  | 
            |
| 218 | 
                - <size key="footerReferenceSize" width="0.0" height="0.0"/>  | 
            |
| 219 | 
                - <inset key="sectionInset" minX="0.0" minY="0.0" maxX="0.0" maxY="0.0"/>  | 
            |
| 220 | 
                - </collectionViewFlowLayout>  | 
            |
| 221 | 
                - <cells>  | 
            |
| 222 | 
                - <collectionViewCell opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" reuseIdentifier="photoDetailCell" id="UJ2-Hm-obI">  | 
            |
| 223 | 
                - <rect key="frame" x="0.0" y="0.0" width="375" height="319"/>  | 
            |
| 224 | 
                - <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>  | 
            |
| 225 | 
                - <view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" insetsLayoutMarginsFromSafeArea="NO">  | 
            |
| 98 | 
                + </view>  | 
            |
| 99 | 
                + <collectionView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" bounces="NO" pagingEnabled="YES" showsHorizontalScrollIndicator="NO" showsVerticalScrollIndicator="NO" bouncesZoom="NO" dataMode="prototypes" prefetchingEnabled="NO" translatesAutoresizingMaskIntoConstraints="NO" id="dtf-M8-otl">  | 
            |
| 100 | 
                + <rect key="frame" x="0.0" y="48" width="375" height="360"/>  | 
            |
| 101 | 
                + <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>  | 
            |
| 102 | 
                + <constraints>  | 
            |
| 103 | 
                + <constraint firstAttribute="height" constant="360" id="4L8-84-zDa"/>  | 
            |
| 104 | 
                + </constraints>  | 
            |
| 105 | 
                + <collectionViewFlowLayout key="collectionViewLayout" scrollDirection="horizontal" minimumLineSpacing="10" minimumInteritemSpacing="10" id="xaD-fO-dLy">  | 
            |
| 106 | 
                + <size key="itemSize" width="375" height="319"/>  | 
            |
| 107 | 
                + <size key="headerReferenceSize" width="0.0" height="0.0"/>  | 
            |
| 108 | 
                + <size key="footerReferenceSize" width="0.0" height="0.0"/>  | 
            |
| 109 | 
                + <inset key="sectionInset" minX="0.0" minY="0.0" maxX="0.0" maxY="0.0"/>  | 
            |
| 110 | 
                + </collectionViewFlowLayout>  | 
            |
| 111 | 
                + <cells>  | 
            |
| 112 | 
                + <collectionViewCell opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" reuseIdentifier="photoDetailImageCell" id="odI-PO-hV5" customClass="PhotoDetailImageCell" customModule="Paiai_iOS" customModuleProvider="target">  | 
            |
| 113 | 
                + <rect key="frame" x="0.0" y="20.5" width="375" height="319"/>  | 
            |
| 114 | 
                + <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>  | 
            |
| 115 | 
                + <view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" insetsLayoutMarginsFromSafeArea="NO">  | 
            |
| 116 | 
                + <rect key="frame" x="0.0" y="0.0" width="375" height="319"/>  | 
            |
| 117 | 
                + <autoresizingMask key="autoresizingMask"/>  | 
            |
| 118 | 
                + <subviews>  | 
            |
| 119 | 
                + <imageView userInteractionEnabled="NO" tag="1010" contentMode="scaleAspectFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="9v7-Ky-ukt">  | 
            |
| 226 | 120 | 
                <rect key="frame" x="0.0" y="0.0" width="375" height="319"/>  | 
            
| 227 | 
                - <autoresizingMask key="autoresizingMask"/>  | 
            |
| 228 | 
                - <subviews>  | 
            |
| 229 | 
                - <imageView userInteractionEnabled="NO" tag="1010" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="ld5-dn-2RB">  | 
            |
| 230 | 
                - <rect key="frame" x="0.0" y="0.0" width="375" height="319"/>  | 
            |
| 231 | 
                - </imageView>  | 
            |
| 232 | 
                - </subviews>  | 
            |
| 233 | 
                - </view>  | 
            |
| 234 | 
                - <constraints>  | 
            |
| 235 | 
                - <constraint firstAttribute="trailing" secondItem="ld5-dn-2RB" secondAttribute="trailing" id="GLQ-xO-RUy"/>  | 
            |
| 236 | 
                - <constraint firstAttribute="bottom" secondItem="ld5-dn-2RB" secondAttribute="bottom" id="Ttz-Zt-E6n"/>  | 
            |
| 237 | 
                - <constraint firstItem="ld5-dn-2RB" firstAttribute="top" secondItem="UJ2-Hm-obI" secondAttribute="top" id="cSU-ct-Cep"/>  | 
            |
| 238 | 
                - <constraint firstItem="ld5-dn-2RB" firstAttribute="leading" secondItem="UJ2-Hm-obI" secondAttribute="leading" id="veK-zA-dfx"/>  | 
            |
| 239 | 
                - </constraints>  | 
            |
| 240 | 
                - </collectionViewCell>  | 
            |
| 241 | 
                - </cells>  | 
            |
| 121 | 
                + </imageView>  | 
            |
| 122 | 
                + </subviews>  | 
            |
| 123 | 
                + </view>  | 
            |
| 124 | 
                + <constraints>  | 
            |
| 125 | 
                + <constraint firstItem="9v7-Ky-ukt" firstAttribute="top" secondItem="odI-PO-hV5" secondAttribute="top" id="PCk-i0-Rwg"/>  | 
            |
| 126 | 
                + <constraint firstAttribute="bottom" secondItem="9v7-Ky-ukt" secondAttribute="bottom" id="R3n-1a-d5C"/>  | 
            |
| 127 | 
                + <constraint firstItem="9v7-Ky-ukt" firstAttribute="leading" secondItem="odI-PO-hV5" secondAttribute="leading" id="YBl-MG-BWY"/>  | 
            |
| 128 | 
                + <constraint firstAttribute="trailing" secondItem="9v7-Ky-ukt" secondAttribute="trailing" id="xxx-f9-RZf"/>  | 
            |
| 129 | 
                + </constraints>  | 
            |
| 242 | 130 | 
                <connections>  | 
            
| 243 | 
                - <outlet property="dataSource" destination="5X4-7Q-chL" id="gmm-ci-u2l"/>  | 
            |
| 244 | 
                - <outlet property="delegate" destination="5X4-7Q-chL" id="RHM-y7-e7G"/>  | 
            |
| 131 | 
                + <outlet property="imageView" destination="9v7-Ky-ukt" id="wbu-di-9Ls"/>  | 
            |
| 245 | 132 | 
                </connections>  | 
            
| 246 | 
                - </collectionView>  | 
            |
| 247 | 
                - </subviews>  | 
            |
| 248 | 
                - <constraints>  | 
            |
| 249 | 
                - <constraint firstAttribute="trailing" secondItem="lAD-oZ-Zgp" secondAttribute="trailing" id="0fy-qh-Y4r"/>  | 
            |
| 250 | 
                - <constraint firstItem="lAD-oZ-Zgp" firstAttribute="leading" secondItem="yVY-TK-vg7" secondAttribute="leading" id="Fcg-rJ-o3p"/>  | 
            |
| 251 | 
                - <constraint firstAttribute="bottom" secondItem="lAD-oZ-Zgp" secondAttribute="bottom" id="JiM-Rf-C9H"/>  | 
            |
| 252 | 
                - <constraint firstItem="lAD-oZ-Zgp" firstAttribute="top" secondItem="yVY-TK-vg7" secondAttribute="top" id="Vdg-DU-USU"/>  | 
            |
| 253 | 
                - </constraints>  | 
            |
| 254 | 
                - </tableViewCellContentView>  | 
            |
| 255 | 
                - <connections>  | 
            |
| 256 | 
                - <outlet property="collectionView" destination="lAD-oZ-Zgp" id="DhH-TY-4el"/>  | 
            |
| 257 | 
                - </connections>  | 
            |
| 258 | 
                - </tableViewCell>  | 
            |
| 259 | 
                - <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" reuseIdentifier="nameCell" rowHeight="47" id="4vg-z0-coW" customClass="DetailPageNameCell" customModule="Paiai_iOS" customModuleProvider="target">  | 
            |
| 260 | 
                - <rect key="frame" x="0.0" y="436" width="375" height="47"/>  | 
            |
| 261 | 
                - <autoresizingMask key="autoresizingMask"/>  | 
            |
| 262 | 
                - <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="4vg-z0-coW" id="cco-VM-Dnu">  | 
            |
| 263 | 
                - <rect key="frame" x="0.0" y="0.0" width="375" height="46.5"/>  | 
            |
| 264 | 
                - <autoresizingMask key="autoresizingMask"/>  | 
            |
| 133 | 
                + </collectionViewCell>  | 
            |
| 134 | 
                + </cells>  | 
            |
| 135 | 
                + </collectionView>  | 
            |
| 136 | 
                + <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="rr6-c2-Nmb" userLabel="Photo Info View">  | 
            |
| 137 | 
                + <rect key="frame" x="0.0" y="408" width="375" height="36"/>  | 
            |
| 265 | 138 | 
                <subviews>  | 
            
| 266 | 
                - <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="名字" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="waZ-4s-ioU">  | 
            |
| 267 | 
                - <rect key="frame" x="41" y="17.5" width="21" height="12"/>  | 
            |
| 139 | 
                + <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="defaultAvatar" translatesAutoresizingMaskIntoConstraints="NO" id="Zj6-ve-uzJ">  | 
            |
| 140 | 
                + <rect key="frame" x="15" y="8" width="20" height="20"/>  | 
            |
| 141 | 
                + <constraints>  | 
            |
| 142 | 
                + <constraint firstAttribute="width" constant="20" id="dui-uv-HdI"/>  | 
            |
| 143 | 
                + <constraint firstAttribute="width" secondItem="Zj6-ve-uzJ" secondAttribute="height" multiplier="1:1" id="mya-LW-5NJ"/>  | 
            |
| 144 | 
                + </constraints>  | 
            |
| 145 | 
                + <userDefinedRuntimeAttributes>  | 
            |
| 146 | 
                + <userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">  | 
            |
| 147 | 
                + <real key="value" value="4"/>  | 
            |
| 148 | 
                + </userDefinedRuntimeAttribute>  | 
            |
| 149 | 
                + </userDefinedRuntimeAttributes>  | 
            |
| 150 | 
                + </imageView>  | 
            |
| 151 | 
                + <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="名字" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="jmc-9F-Uzr">  | 
            |
| 152 | 
                + <rect key="frame" x="41" y="12" width="21" height="12"/>  | 
            |
| 268 | 153 | 
                <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>  | 
            
| 269 | 154 | 
                <fontDescription key="fontDescription" type="system" pointSize="10"/>  | 
            
| 270 | 155 | 
                <color key="textColor" red="0.59999999999999998" green="0.59999999999999998" blue="0.59999999999999998" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>  | 
            
| 271 | 156 | 
                <nil key="highlightedColor"/>  | 
            
| 272 | 157 | 
                </label>  | 
            
| 273 | 
                - <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="icon-记录" translatesAutoresizingMaskIntoConstraints="NO" id="jOJ-N0-rYP">  | 
            |
| 274 | 
                - <rect key="frame" x="286" y="5.5" width="36" height="36"/>  | 
            |
| 158 | 
                + <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="icon-time" translatesAutoresizingMaskIntoConstraints="NO" id="xXQ-Hj-wzP">  | 
            |
| 159 | 
                + <rect key="frame" x="286" y="0.0" width="36" height="36"/>  | 
            |
| 275 | 160 | 
                </imageView>  | 
            
| 276 | 
                - <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="5分钟前" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="d9Q-3T-h1t">  | 
            |
| 277 | 
                - <rect key="frame" x="328" y="17.5" width="37" height="12"/>  | 
            |
| 161 | 
                + <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="5分钟前" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="QpI-Mp-URP">  | 
            |
| 162 | 
                + <rect key="frame" x="332" y="12" width="37" height="12"/>  | 
            |
| 278 | 163 | 
                <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>  | 
            
| 279 | 164 | 
                <fontDescription key="fontDescription" type="system" pointSize="10"/>  | 
            
| 280 | 165 | 
                <color key="textColor" red="0.59999999999999998" green="0.59999999999999998" blue="0.59999999999999998" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>  | 
            
| 281 | 166 | 
                <nil key="highlightedColor"/>  | 
            
| 282 | 167 | 
                </label>  | 
            
| 283 | 
                - <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="默认头像" translatesAutoresizingMaskIntoConstraints="NO" id="ngb-KR-cA6">  | 
            |
| 284 | 
                - <rect key="frame" x="15" y="13.5" width="20" height="20"/>  | 
            |
| 285 | 
                - <constraints>  | 
            |
| 286 | 
                - <constraint firstAttribute="width" constant="20" id="cSl-og-Uae"/>  | 
            |
| 287 | 
                - <constraint firstAttribute="width" secondItem="ngb-KR-cA6" secondAttribute="height" id="fbg-yA-QyN"/>  | 
            |
| 288 | 
                - </constraints>  | 
            |
| 289 | 
                - <userDefinedRuntimeAttributes>  | 
            |
| 290 | 
                - <userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">  | 
            |
| 291 | 
                - <real key="value" value="4"/>  | 
            |
| 292 | 
                - </userDefinedRuntimeAttribute>  | 
            |
| 293 | 
                - </userDefinedRuntimeAttributes>  | 
            |
| 294 | 
                - </imageView>  | 
            |
| 295 | 168 | 
                </subviews>  | 
            
| 169 | 
                + <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>  | 
            |
| 296 | 170 | 
                <constraints>  | 
            
| 297 | 
                - <constraint firstItem="d9Q-3T-h1t" firstAttribute="leading" secondItem="jOJ-N0-rYP" secondAttribute="trailing" constant="6" id="DFx-VY-iOc"/>  | 
            |
| 298 | 
                - <constraint firstItem="waZ-4s-ioU" firstAttribute="leading" secondItem="ngb-KR-cA6" secondAttribute="trailing" constant="6" id="Yai-Qc-Kxw"/>  | 
            |
| 299 | 
                - <constraint firstItem="waZ-4s-ioU" firstAttribute="centerY" secondItem="cco-VM-Dnu" secondAttribute="centerY" id="aUY-C4-Hbb"/>  | 
            |
| 300 | 
                - <constraint firstItem="ngb-KR-cA6" firstAttribute="width" secondItem="ngb-KR-cA6" secondAttribute="height" id="ery-Ch-bGL"/>  | 
            |
| 301 | 
                - <constraint firstItem="jOJ-N0-rYP" firstAttribute="centerY" secondItem="waZ-4s-ioU" secondAttribute="centerY" id="m0E-Mf-ee0"/>  | 
            |
| 302 | 
                - <constraint firstItem="waZ-4s-ioU" firstAttribute="centerY" secondItem="ngb-KR-cA6" secondAttribute="centerY" id="nUJ-pU-dXK"/>  | 
            |
| 303 | 
                - <constraint firstItem="ngb-KR-cA6" firstAttribute="leading" secondItem="cco-VM-Dnu" secondAttribute="leading" constant="15" id="vfD-Pc-Dfp"/>  | 
            |
| 304 | 
                - <constraint firstAttribute="trailing" secondItem="d9Q-3T-h1t" secondAttribute="trailing" constant="10" id="w69-ZT-64v"/>  | 
            |
| 305 | 
                - <constraint firstItem="d9Q-3T-h1t" firstAttribute="centerY" secondItem="jOJ-N0-rYP" secondAttribute="centerY" id="zau-ES-xhb"/>  | 
            |
| 171 | 
                + <constraint firstAttribute="trailing" secondItem="QpI-Mp-URP" secondAttribute="trailing" constant="6" id="GDW-SR-ql9"/>  | 
            |
| 172 | 
                + <constraint firstItem="QpI-Mp-URP" firstAttribute="leading" secondItem="xXQ-Hj-wzP" secondAttribute="trailing" constant="10" id="NNQ-Rx-3ip"/>  | 
            |
| 173 | 
                + <constraint firstItem="Zj6-ve-uzJ" firstAttribute="leading" secondItem="rr6-c2-Nmb" secondAttribute="leading" constant="15" id="NWK-xB-He1"/>  | 
            |
| 174 | 
                + <constraint firstItem="jmc-9F-Uzr" firstAttribute="centerY" secondItem="rr6-c2-Nmb" secondAttribute="centerY" id="PsY-nq-8ao"/>  | 
            |
| 175 | 
                + <constraint firstAttribute="height" constant="36" id="SUQ-5X-XLy"/>  | 
            |
| 176 | 
                + <constraint firstItem="jmc-9F-Uzr" firstAttribute="leading" secondItem="Zj6-ve-uzJ" secondAttribute="trailing" constant="6" id="cr3-c0-hhq"/>  | 
            |
| 177 | 
                + <constraint firstItem="QpI-Mp-URP" firstAttribute="centerY" secondItem="rr6-c2-Nmb" secondAttribute="centerY" id="eBQ-qI-A8r"/>  | 
            |
| 178 | 
                + <constraint firstItem="Zj6-ve-uzJ" firstAttribute="centerY" secondItem="rr6-c2-Nmb" secondAttribute="centerY" id="t6b-zO-3rf"/>  | 
            |
| 179 | 
                + <constraint firstItem="xXQ-Hj-wzP" firstAttribute="centerY" secondItem="rr6-c2-Nmb" secondAttribute="centerY" id="x1T-b0-thB"/>  | 
            |
| 306 | 180 | 
                </constraints>  | 
            
| 307 | 
                - </tableViewCellContentView>  | 
            |
| 308 | 
                - <connections>  | 
            |
| 309 | 
                - <outlet property="personImage" destination="ngb-KR-cA6" id="UKC-bx-df1"/>  | 
            |
| 310 | 
                - <outlet property="personName" destination="waZ-4s-ioU" id="7kC-Jy-joK"/>  | 
            |
| 311 | 
                - <outlet property="time" destination="d9Q-3T-h1t" id="8ku-p3-pIy"/>  | 
            |
| 312 | 
                - </connections>  | 
            |
| 313 | 
                - </tableViewCell>  | 
            |
| 314 | 
                - <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" reuseIdentifier="thumbupHeadCell" rowHeight="45" id="drb-Ur-Tep">  | 
            |
| 315 | 
                - <rect key="frame" x="0.0" y="483" width="375" height="45"/>  | 
            |
| 316 | 
                - <autoresizingMask key="autoresizingMask"/>  | 
            |
| 317 | 
                - <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="drb-Ur-Tep" id="BWN-JQ-YDl">  | 
            |
| 318 | 
                - <rect key="frame" x="0.0" y="0.0" width="375" height="44.5"/>  | 
            |
| 319 | 
                - <autoresizingMask key="autoresizingMask"/>  | 
            |
| 181 | 
                + </view>  | 
            |
| 182 | 
                + <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="q4A-0r-b7Z" userLabel="Thumbup Head View">  | 
            |
| 183 | 
                + <rect key="frame" x="0.0" y="444" width="375" height="44"/>  | 
            |
| 320 | 184 | 
                <subviews>  | 
            
| 321 | 
                - <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="赞" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="G5n-Xf-7Hy">  | 
            |
| 322 | 
                - <rect key="frame" x="57" y="14" width="15" height="17"/>  | 
            |
| 185 | 
                + <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="icon-thumbup" translatesAutoresizingMaskIntoConstraints="NO" id="haH-1L-wfF">  | 
            |
| 186 | 
                + <rect key="frame" x="15" y="4" width="36" height="36"/>  | 
            |
| 187 | 
                + </imageView>  | 
            |
| 188 | 
                + <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="赞" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="vrx-vV-ymg">  | 
            |
| 189 | 
                + <rect key="frame" x="57" y="13.5" width="14.5" height="17"/>  | 
            |
| 323 | 190 | 
                <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>  | 
            
| 324 | 191 | 
                <fontDescription key="fontDescription" type="system" pointSize="14"/>  | 
            
| 325 | 192 | 
                <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>  | 
            
| 326 | 193 | 
                <nil key="highlightedColor"/>  | 
            
| 327 | 194 | 
                </label>  | 
            
| 328 | 
                - <imageView userInteractionEnabled="NO" tag="1008" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="list-arrow" translatesAutoresizingMaskIntoConstraints="NO" id="pC6-7A-WSm">  | 
            |
| 329 | 
                - <rect key="frame" x="349" y="14.5" width="16" height="16"/>  | 
            |
| 330 | 
                - </imageView>  | 
            |
| 331 | 
                - <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="icon-赞" translatesAutoresizingMaskIntoConstraints="NO" id="jXa-8T-THD">  | 
            |
| 332 | 
                - <rect key="frame" x="15" y="4.5" width="36" height="36"/>  | 
            |
| 333 | 
                - </imageView>  | 
            |
| 334 | 
                - <label opaque="NO" userInteractionEnabled="NO" tag="1001" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="(0)" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="60x-jR-ECW">  | 
            |
| 335 | 
                - <rect key="frame" x="72" y="15" width="17" height="15"/>  | 
            |
| 195 | 
                + <label opaque="NO" userInteractionEnabled="NO" tag="1002" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="(0)" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="h88-PP-cvG">  | 
            |
| 196 | 
                + <rect key="frame" x="77.5" y="14.5" width="17" height="15"/>  | 
            |
| 336 | 197 | 
                <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>  | 
            
| 337 | 198 | 
                <fontDescription key="fontDescription" type="system" pointSize="12"/>  | 
            
| 338 | 199 | 
                <color key="textColor" red="0.59999999999999998" green="0.59999999999999998" blue="0.59999999999999998" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>  | 
            
| 339 | 200 | 
                <nil key="highlightedColor"/>  | 
            
| 340 | 201 | 
                </label>  | 
            
| 341 | 
                - <button opaque="NO" tag="1011" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="LBo-30-wNB">  | 
            |
| 342 | 
                - <rect key="frame" x="0.0" y="0.0" width="375" height="44.5"/>  | 
            |
| 343 | 
                - </button>  | 
            |
| 202 | 
                + <imageView userInteractionEnabled="NO" tag="1008" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="list-arrow" translatesAutoresizingMaskIntoConstraints="NO" id="sg5-Nx-u2C">  | 
            |
| 203 | 
                + <rect key="frame" x="341" y="4" width="24" height="36"/>  | 
            |
| 204 | 
                + </imageView>  | 
            |
| 344 | 205 | 
                </subviews>  | 
            
| 345 | 
                - <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>  | 
            |
| 206 | 
                + <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>  | 
            |
| 346 | 207 | 
                <constraints>  | 
            
| 347 | 
                - <constraint firstItem="60x-jR-ECW" firstAttribute="leading" secondItem="G5n-Xf-7Hy" secondAttribute="trailing" id="9q1-CU-lc7"/>  | 
            |
| 348 | 
                - <constraint firstItem="pC6-7A-WSm" firstAttribute="centerY" secondItem="BWN-JQ-YDl" secondAttribute="centerY" id="GBf-JN-0V2"/>  | 
            |
| 349 | 
                - <constraint firstItem="jXa-8T-THD" firstAttribute="leading" secondItem="BWN-JQ-YDl" secondAttribute="leading" constant="15" id="GLF-x3-OKn"/>  | 
            |
| 350 | 
                - <constraint firstItem="LBo-30-wNB" firstAttribute="leading" secondItem="BWN-JQ-YDl" secondAttribute="leading" id="JoW-OJ-4RR"/>  | 
            |
| 351 | 
                - <constraint firstItem="60x-jR-ECW" firstAttribute="centerY" secondItem="G5n-Xf-7Hy" secondAttribute="centerY" id="KDe-lJ-k9I"/>  | 
            |
| 352 | 
                - <constraint firstAttribute="trailing" secondItem="pC6-7A-WSm" secondAttribute="trailing" constant="10" id="TIX-Ap-qwt"/>  | 
            |
| 353 | 
                - <constraint firstItem="G5n-Xf-7Hy" firstAttribute="centerY" secondItem="jXa-8T-THD" secondAttribute="centerY" id="aY4-8A-f3G"/>  | 
            |
| 354 | 
                - <constraint firstAttribute="trailing" secondItem="LBo-30-wNB" secondAttribute="trailing" id="mO4-S9-lSy"/>  | 
            |
| 355 | 
                - <constraint firstItem="jXa-8T-THD" firstAttribute="centerY" secondItem="BWN-JQ-YDl" secondAttribute="centerY" id="nGe-eB-vLt"/>  | 
            |
| 356 | 
                - <constraint firstAttribute="bottom" secondItem="LBo-30-wNB" secondAttribute="bottom" id="rzW-nS-eo8"/>  | 
            |
| 357 | 
                - <constraint firstItem="G5n-Xf-7Hy" firstAttribute="leading" secondItem="jXa-8T-THD" secondAttribute="trailing" constant="6" id="vMx-nk-gUB"/>  | 
            |
| 358 | 
                - <constraint firstItem="LBo-30-wNB" firstAttribute="top" secondItem="BWN-JQ-YDl" secondAttribute="top" id="xOJ-uY-wdZ"/>  | 
            |
| 208 | 
                + <constraint firstItem="vrx-vV-ymg" firstAttribute="centerY" secondItem="q4A-0r-b7Z" secondAttribute="centerY" id="2aB-mH-SX5"/>  | 
            |
| 209 | 
                + <constraint firstAttribute="trailing" secondItem="sg5-Nx-u2C" secondAttribute="trailing" constant="10" id="Xcf-rE-5in"/>  | 
            |
| 210 | 
                + <constraint firstItem="haH-1L-wfF" firstAttribute="leading" secondItem="q4A-0r-b7Z" secondAttribute="leading" constant="15" id="coB-Ko-wkQ"/>  | 
            |
| 211 | 
                + <constraint firstAttribute="height" constant="44" id="iuu-F3-RtX"/>  | 
            |
| 212 | 
                + <constraint firstItem="haH-1L-wfF" firstAttribute="centerY" secondItem="q4A-0r-b7Z" secondAttribute="centerY" id="j94-Un-Fr7"/>  | 
            |
| 213 | 
                + <constraint firstItem="h88-PP-cvG" firstAttribute="centerY" secondItem="q4A-0r-b7Z" secondAttribute="centerY" id="miO-hD-cUC"/>  | 
            |
| 214 | 
                + <constraint firstItem="h88-PP-cvG" firstAttribute="leading" secondItem="vrx-vV-ymg" secondAttribute="trailing" constant="6" id="okS-hS-zFj"/>  | 
            |
| 215 | 
                + <constraint firstItem="vrx-vV-ymg" firstAttribute="leading" secondItem="haH-1L-wfF" secondAttribute="trailing" constant="6" id="rQM-ic-NS0"/>  | 
            |
| 216 | 
                + <constraint firstItem="sg5-Nx-u2C" firstAttribute="centerY" secondItem="q4A-0r-b7Z" secondAttribute="centerY" id="yjO-bc-Du8"/>  | 
            |
| 359 | 217 | 
                </constraints>  | 
            
| 360 | 
                - </tableViewCellContentView>  | 
            |
| 361 | 
                - </tableViewCell>  | 
            |
| 362 | 
                - <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" reuseIdentifier="thumbupCell" rowHeight="40" id="53z-YY-Hrb" customClass="DetailthumbupImagesCell" customModule="Paiai_iOS" customModuleProvider="target">  | 
            |
| 363 | 
                - <rect key="frame" x="0.0" y="528" width="375" height="40"/>  | 
            |
| 364 | 
                - <autoresizingMask key="autoresizingMask"/>  | 
            |
| 365 | 
                - <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="53z-YY-Hrb" id="L28-C6-ile">  | 
            |
| 366 | 
                - <rect key="frame" x="0.0" y="0.0" width="375" height="39.5"/>  | 
            |
| 367 | 
                - <autoresizingMask key="autoresizingMask"/>  | 
            |
| 368 | 
                - <subviews>  | 
            |
| 369 | 
                - <scrollView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="MCX-77-Qga">  | 
            |
| 370 | 
                - <rect key="frame" x="0.0" y="0.0" width="375" height="39.5"/>  | 
            |
| 371 | 
                - </scrollView>  | 
            |
| 372 | 
                - </subviews>  | 
            |
| 218 | 
                + </view>  | 
            |
| 219 | 
                + <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Zde-8U-5Bl" userLabel="Thumbup View">  | 
            |
| 220 | 
                + <rect key="frame" x="0.0" y="488" width="375" height="1"/>  | 
            |
| 221 | 
                + <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>  | 
            |
| 373 | 222 | 
                <constraints>  | 
            
| 374 | 
                - <constraint firstAttribute="trailing" secondItem="MCX-77-Qga" secondAttribute="trailing" id="2pY-hr-G4z"/>  | 
            |
| 375 | 
                - <constraint firstItem="MCX-77-Qga" firstAttribute="leading" secondItem="L28-C6-ile" secondAttribute="leading" id="YJo-K5-cWs"/>  | 
            |
| 376 | 
                - <constraint firstAttribute="bottom" secondItem="MCX-77-Qga" secondAttribute="bottom" id="nby-bv-mI5"/>  | 
            |
| 377 | 
                - <constraint firstItem="MCX-77-Qga" firstAttribute="top" secondItem="L28-C6-ile" secondAttribute="top" id="wbM-of-emg"/>  | 
            |
| 223 | 
                + <constraint firstAttribute="height" constant="1" id="fc8-6l-lEC"/>  | 
            |
| 378 | 224 | 
                </constraints>  | 
            
| 379 | 
                - </tableViewCellContentView>  | 
            |
| 380 | 
                - <connections>  | 
            |
| 381 | 
                - <outlet property="imagesScrollView" destination="MCX-77-Qga" id="qdA-ux-1Op"/>  | 
            |
| 382 | 
                - </connections>  | 
            |
| 383 | 
                - </tableViewCell>  | 
            |
| 384 | 
                - <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" reuseIdentifier="comentHeadCell" rowHeight="45" id="avB-IM-8sZ">  | 
            |
| 385 | 
                - <rect key="frame" x="0.0" y="568" width="375" height="45"/>  | 
            |
| 386 | 
                - <autoresizingMask key="autoresizingMask"/>  | 
            |
| 387 | 
                - <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="avB-IM-8sZ" id="B2U-lF-5Lm">  | 
            |
| 388 | 
                - <rect key="frame" x="0.0" y="0.0" width="375" height="44.5"/>  | 
            |
| 389 | 
                - <autoresizingMask key="autoresizingMask"/>  | 
            |
| 225 | 
                + </view>  | 
            |
| 226 | 
                + <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="IOw-Xw-2vP" userLabel="Comment Head View">  | 
            |
| 227 | 
                + <rect key="frame" x="0.0" y="489" width="375" height="44"/>  | 
            |
| 390 | 228 | 
                <subviews>  | 
            
| 391 | 
                - <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="评论" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="sbI-Yk-yw3">  | 
            |
| 392 | 
                - <rect key="frame" x="57" y="14" width="29" height="17"/>  | 
            |
| 229 | 
                + <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="icon-comment" translatesAutoresizingMaskIntoConstraints="NO" id="zTQ-T2-IMt">  | 
            |
| 230 | 
                + <rect key="frame" x="15" y="4" width="36" height="36"/>  | 
            |
| 231 | 
                + </imageView>  | 
            |
| 232 | 
                + <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="评论" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="vLK-B7-FQc">  | 
            |
| 233 | 
                + <rect key="frame" x="57" y="13.5" width="29" height="17"/>  | 
            |
| 393 | 234 | 
                <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>  | 
            
| 394 | 235 | 
                <fontDescription key="fontDescription" type="system" pointSize="14"/>  | 
            
| 395 | 236 | 
                <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>  | 
            
| 396 | 237 | 
                <nil key="highlightedColor"/>  | 
            
| 397 | 238 | 
                </label>  | 
            
| 398 | 
                - <imageView userInteractionEnabled="NO" tag="1009" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="list-arrow" translatesAutoresizingMaskIntoConstraints="NO" id="GOS-Xt-kBa">  | 
            |
| 399 | 
                - <rect key="frame" x="349" y="14.5" width="16" height="16"/>  | 
            |
| 400 | 
                - </imageView>  | 
            |
| 401 | 
                - <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="icon-评论" translatesAutoresizingMaskIntoConstraints="NO" id="7bL-8L-k4P">  | 
            |
| 402 | 
                - <rect key="frame" x="15" y="4.5" width="36" height="36"/>  | 
            |
| 403 | 
                - </imageView>  | 
            |
| 404 | 
                - <label opaque="NO" userInteractionEnabled="NO" tag="1002" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="(0)" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="vvS-oJ-TqJ">  | 
            |
| 405 | 
                - <rect key="frame" x="86" y="15" width="17" height="15"/>  | 
            |
| 239 | 
                + <label opaque="NO" userInteractionEnabled="NO" tag="1002" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="(0)" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="cuT-s1-NnA">  | 
            |
| 240 | 
                + <rect key="frame" x="92" y="14.5" width="17" height="15"/>  | 
            |
| 406 | 241 | 
                <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>  | 
            
| 407 | 242 | 
                <fontDescription key="fontDescription" type="system" pointSize="12"/>  | 
            
| 408 | 243 | 
                <color key="textColor" red="0.59999999999999998" green="0.59999999999999998" blue="0.59999999999999998" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>  | 
            
| 409 | 244 | 
                <nil key="highlightedColor"/>  | 
            
| 410 | 245 | 
                </label>  | 
            
| 411 | 
                - <button opaque="NO" tag="1012" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="qe6-le-PxN">  | 
            |
| 412 | 
                - <rect key="frame" x="0.0" y="0.0" width="375" height="44.5"/>  | 
            |
| 413 | 
                - </button>  | 
            |
| 246 | 
                + <imageView userInteractionEnabled="NO" tag="1009" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="list-arrow" translatesAutoresizingMaskIntoConstraints="NO" id="ns5-B1-ilP">  | 
            |
| 247 | 
                + <rect key="frame" x="341" y="4" width="24" height="36"/>  | 
            |
| 248 | 
                + </imageView>  | 
            |
| 414 | 249 | 
                </subviews>  | 
            
| 415 | 
                - <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>  | 
            |
| 250 | 
                + <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>  | 
            |
| 416 | 251 | 
                <constraints>  | 
            
| 417 | 
                - <constraint firstAttribute="trailing" secondItem="GOS-Xt-kBa" secondAttribute="trailing" constant="10" id="44I-Im-laR"/>  | 
            |
| 418 | 
                - <constraint firstItem="7bL-8L-k4P" firstAttribute="centerY" secondItem="B2U-lF-5Lm" secondAttribute="centerY" id="DvT-0Q-xhb"/>  | 
            |
| 419 | 
                - <constraint firstItem="sbI-Yk-yw3" firstAttribute="centerY" secondItem="7bL-8L-k4P" secondAttribute="centerY" id="Ee0-la-oHg"/>  | 
            |
| 420 | 
                - <constraint firstAttribute="bottom" secondItem="qe6-le-PxN" secondAttribute="bottom" id="HHp-89-beY"/>  | 
            |
| 421 | 
                - <constraint firstItem="7bL-8L-k4P" firstAttribute="leading" secondItem="B2U-lF-5Lm" secondAttribute="leading" constant="15" id="LAr-Q4-Zfc"/>  | 
            |
| 422 | 
                - <constraint firstAttribute="trailing" secondItem="qe6-le-PxN" secondAttribute="trailing" id="MzB-GI-zPj"/>  | 
            |
| 423 | 
                - <constraint firstItem="qe6-le-PxN" firstAttribute="top" secondItem="B2U-lF-5Lm" secondAttribute="top" id="OK4-7y-Ty6"/>  | 
            |
| 424 | 
                - <constraint firstItem="sbI-Yk-yw3" firstAttribute="leading" secondItem="7bL-8L-k4P" secondAttribute="trailing" constant="6" id="VUL-1O-eDc"/>  | 
            |
| 425 | 
                - <constraint firstItem="vvS-oJ-TqJ" firstAttribute="leading" secondItem="sbI-Yk-yw3" secondAttribute="trailing" id="ekQ-rb-Mq7"/>  | 
            |
| 426 | 
                - <constraint firstItem="vvS-oJ-TqJ" firstAttribute="centerY" secondItem="sbI-Yk-yw3" secondAttribute="centerY" id="fed-Gs-JKg"/>  | 
            |
| 427 | 
                - <constraint firstItem="GOS-Xt-kBa" firstAttribute="centerY" secondItem="B2U-lF-5Lm" secondAttribute="centerY" id="gap-OK-zCS"/>  | 
            |
| 428 | 
                - <constraint firstItem="qe6-le-PxN" firstAttribute="leading" secondItem="B2U-lF-5Lm" secondAttribute="leading" id="iNa-2Q-Opq"/>  | 
            |
| 252 | 
                + <constraint firstAttribute="height" constant="44" id="3Tu-zh-sgQ"/>  | 
            |
| 253 | 
                + <constraint firstItem="vLK-B7-FQc" firstAttribute="leading" secondItem="zTQ-T2-IMt" secondAttribute="trailing" constant="6" id="DSt-2x-Aqs"/>  | 
            |
| 254 | 
                + <constraint firstItem="zTQ-T2-IMt" firstAttribute="centerY" secondItem="IOw-Xw-2vP" secondAttribute="centerY" id="MFO-T3-4Bi"/>  | 
            |
| 255 | 
                + <constraint firstItem="cuT-s1-NnA" firstAttribute="centerY" secondItem="IOw-Xw-2vP" secondAttribute="centerY" id="N92-Fg-wmf"/>  | 
            |
| 256 | 
                + <constraint firstAttribute="trailing" secondItem="ns5-B1-ilP" secondAttribute="trailing" constant="10" id="Q1P-ZJ-bnb"/>  | 
            |
| 257 | 
                + <constraint firstItem="vLK-B7-FQc" firstAttribute="centerY" secondItem="IOw-Xw-2vP" secondAttribute="centerY" id="fcK-Ns-e87"/>  | 
            |
| 258 | 
                + <constraint firstItem="cuT-s1-NnA" firstAttribute="leading" secondItem="vLK-B7-FQc" secondAttribute="trailing" constant="6" id="kub-1K-GZD"/>  | 
            |
| 259 | 
                + <constraint firstItem="zTQ-T2-IMt" firstAttribute="leading" secondItem="IOw-Xw-2vP" secondAttribute="leading" constant="15" id="qjz-mA-ueh"/>  | 
            |
| 260 | 
                + <constraint firstItem="ns5-B1-ilP" firstAttribute="centerY" secondItem="IOw-Xw-2vP" secondAttribute="centerY" id="zaJ-pH-gPl"/>  | 
            |
| 429 | 261 | 
                </constraints>  | 
            
| 430 | 
                - </tableViewCellContentView>  | 
            |
| 431 | 
                - </tableViewCell>  | 
            |
| 432 | 
                - <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" reuseIdentifier="comentCell" rowHeight="95" id="DCX-Km-bjG" customClass="DetailCommentCell" customModule="Paiai_iOS" customModuleProvider="target">  | 
            |
| 433 | 
                - <rect key="frame" x="0.0" y="613" width="375" height="95"/>  | 
            |
| 262 | 
                + </view>  | 
            |
| 263 | 
                + </subviews>  | 
            |
| 264 | 
                + <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>  | 
            |
| 265 | 
                + <constraints>  | 
            |
| 266 | 
                + <constraint firstItem="rr6-c2-Nmb" firstAttribute="leading" secondItem="kJj-s4-SK1" secondAttribute="leading" id="0SQ-nj-VPb"/>  | 
            |
| 267 | 
                + <constraint firstItem="dtf-M8-otl" firstAttribute="top" secondItem="rL2-VZ-0O7" secondAttribute="bottom" id="5yA-SJ-n2O"/>  | 
            |
| 268 | 
                + <constraint firstAttribute="trailing" secondItem="rL2-VZ-0O7" secondAttribute="trailing" id="9Fd-m1-g5N"/>  | 
            |
| 269 | 
                + <constraint firstAttribute="trailing" secondItem="IOw-Xw-2vP" secondAttribute="trailing" id="HO5-eq-e4w"/>  | 
            |
| 270 | 
                + <constraint firstItem="dtf-M8-otl" firstAttribute="leading" secondItem="kJj-s4-SK1" secondAttribute="leading" id="HaR-NE-PdQ"/>  | 
            |
| 271 | 
                + <constraint firstItem="q4A-0r-b7Z" firstAttribute="leading" secondItem="kJj-s4-SK1" secondAttribute="leading" id="LbP-SU-Mc1"/>  | 
            |
| 272 | 
                + <constraint firstItem="IOw-Xw-2vP" firstAttribute="top" secondItem="Zde-8U-5Bl" secondAttribute="bottom" id="QU5-ve-FU8"/>  | 
            |
| 273 | 
                + <constraint firstAttribute="trailing" secondItem="Zde-8U-5Bl" secondAttribute="trailing" id="QiZ-Na-0ZD"/>  | 
            |
| 274 | 
                + <constraint firstItem="q4A-0r-b7Z" firstAttribute="top" secondItem="rr6-c2-Nmb" secondAttribute="bottom" id="Rdi-IX-jRd"/>  | 
            |
| 275 | 
                + <constraint firstItem="rL2-VZ-0O7" firstAttribute="top" secondItem="kJj-s4-SK1" secondAttribute="top" id="ePm-7e-WNF"/>  | 
            |
| 276 | 
                + <constraint firstAttribute="trailing" secondItem="dtf-M8-otl" secondAttribute="trailing" id="eRL-0a-k9R"/>  | 
            |
| 277 | 
                + <constraint firstItem="IOw-Xw-2vP" firstAttribute="leading" secondItem="kJj-s4-SK1" secondAttribute="leading" id="fXq-hn-nah"/>  | 
            |
| 278 | 
                + <constraint firstAttribute="bottom" secondItem="IOw-Xw-2vP" secondAttribute="bottom" id="gyd-SZ-DKX"/>  | 
            |
| 279 | 
                + <constraint firstAttribute="trailing" secondItem="rr6-c2-Nmb" secondAttribute="trailing" id="jux-w6-IPv"/>  | 
            |
| 280 | 
                + <constraint firstItem="rr6-c2-Nmb" firstAttribute="top" secondItem="dtf-M8-otl" secondAttribute="bottom" id="oGA-xB-bcp"/>  | 
            |
| 281 | 
                + <constraint firstItem="Zde-8U-5Bl" firstAttribute="top" secondItem="q4A-0r-b7Z" secondAttribute="bottom" id="sGh-IF-x0B"/>  | 
            |
| 282 | 
                + <constraint firstItem="rL2-VZ-0O7" firstAttribute="leading" secondItem="kJj-s4-SK1" secondAttribute="leading" id="w0b-Fi-mSe"/>  | 
            |
| 283 | 
                + <constraint firstItem="Zde-8U-5Bl" firstAttribute="leading" secondItem="kJj-s4-SK1" secondAttribute="leading" id="wXy-sO-XoE"/>  | 
            |
| 284 | 
                + <constraint firstAttribute="trailing" secondItem="q4A-0r-b7Z" secondAttribute="trailing" id="wuV-6N-4YD"/>  | 
            |
| 285 | 
                + </constraints>  | 
            |
| 286 | 
                + </view>  | 
            |
| 287 | 
                + <prototypes>  | 
            |
| 288 | 
                + <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" reuseIdentifier="photoDetailCommentCell" rowHeight="95" id="DCX-Km-bjG" customClass="PhotoDetailCommentCell" customModule="Paiai_iOS" customModuleProvider="target">  | 
            |
| 289 | 
                + <rect key="frame" x="0.0" y="561" width="375" height="95"/>  | 
            |
| 434 | 290 | 
                <autoresizingMask key="autoresizingMask"/>  | 
            
| 435 | 291 | 
                <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="DCX-Km-bjG" id="ncE-AG-MIP">  | 
            
| 436 | 292 | 
                <rect key="frame" x="0.0" y="0.0" width="375" height="94.5"/>  | 
            
| 437 | 293 | 
                <autoresizingMask key="autoresizingMask"/>  | 
            
| 438 | 294 | 
                <subviews>  | 
            
| 439 | 
                - <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="默认头像" translatesAutoresizingMaskIntoConstraints="NO" id="str-tM-QWN">  | 
            |
| 295 | 
                + <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="defaultAvatar" translatesAutoresizingMaskIntoConstraints="NO" id="str-tM-QWN">  | 
            |
| 440 | 296 | 
                <rect key="frame" x="15" y="10" width="28" height="28"/>  | 
            
| 441 | 297 | 
                <constraints>  | 
            
| 442 | 
                - <constraint firstAttribute="width" secondItem="str-tM-QWN" secondAttribute="height" id="PB6-88-f0G"/>  | 
            |
| 443 | 298 | 
                <constraint firstAttribute="width" constant="28" id="VSg-1T-4Hy"/>  | 
            
| 444 | 299 | 
                </constraints>  | 
            
| 445 | 300 | 
                <userDefinedRuntimeAttributes>  | 
            
                @@ -455,13 +310,6 @@  | 
            ||
| 455 | 310 | 
                <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>  | 
            
| 456 | 311 | 
                <nil key="highlightedColor"/>  | 
            
| 457 | 312 | 
                </label>  | 
            
| 458 | 
                - <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="iwc-4j-TRS">  | 
            |
| 459 | 
                - <rect key="frame" x="53" y="34" width="312" height="29"/>  | 
            |
| 460 | 
                - <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>  | 
            |
| 461 | 
                - <fontDescription key="fontDescription" type="system" pointSize="12"/>  | 
            |
| 462 | 
                - <color key="textColor" red="0.40000000000000002" green="0.40000000000000002" blue="0.40000000000000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>  | 
            |
| 463 | 
                - <nil key="highlightedColor"/>  | 
            |
| 464 | 
                - </label>  | 
            |
| 465 | 313 | 
                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="0分钟前" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="MsN-4R-lt2">  | 
            
| 466 | 314 | 
                <rect key="frame" x="327" y="12" width="38" height="12"/>  | 
            
| 467 | 315 | 
                <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>  | 
            
                @@ -469,17 +317,24 @@  | 
            ||
| 469 | 317 | 
                <color key="textColor" red="0.59999999999999998" green="0.59999999999999998" blue="0.59999999999999998" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>  | 
            
| 470 | 318 | 
                <nil key="highlightedColor"/>  | 
            
| 471 | 319 | 
                </label>  | 
            
| 320 | 
                + <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="iwc-4j-TRS">  | 
            |
| 321 | 
                + <rect key="frame" x="15" y="44" width="350" height="50.5"/>  | 
            |
| 322 | 
                + <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>  | 
            |
| 323 | 
                + <fontDescription key="fontDescription" type="system" pointSize="12"/>  | 
            |
| 324 | 
                + <color key="textColor" red="0.40000000000000002" green="0.40000000000000002" blue="0.40000000000000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>  | 
            |
| 325 | 
                + <nil key="highlightedColor"/>  | 
            |
| 326 | 
                + </label>  | 
            |
| 472 | 327 | 
                </subviews>  | 
            
| 473 | 328 | 
                <constraints>  | 
            
| 474 | 
                - <constraint firstItem="iwc-4j-TRS" firstAttribute="top" secondItem="u6l-UB-FoK" secondAttribute="bottom" constant="8" id="5LY-xA-5ML"/>  | 
            |
| 329 | 
                + <constraint firstItem="iwc-4j-TRS" firstAttribute="top" secondItem="str-tM-QWN" secondAttribute="bottom" constant="6" id="2qq-j5-mKw"/>  | 
            |
| 475 | 330 | 
                <constraint firstItem="MsN-4R-lt2" firstAttribute="centerY" secondItem="u6l-UB-FoK" secondAttribute="centerY" id="9qq-6O-Vhb"/>  | 
            
| 476 | 
                - <constraint firstAttribute="trailing" secondItem="iwc-4j-TRS" secondAttribute="trailing" constant="10" id="TMI-os-LvC"/>  | 
            |
| 477 | 
                - <constraint firstItem="str-tM-QWN" firstAttribute="width" secondItem="str-tM-QWN" secondAttribute="height" id="c0x-MP-hUB"/>  | 
            |
| 331 | 
                + <constraint firstAttribute="trailing" secondItem="iwc-4j-TRS" secondAttribute="trailing" constant="10" id="VFy-cP-ts4"/>  | 
            |
| 332 | 
                + <constraint firstItem="iwc-4j-TRS" firstAttribute="leading" secondItem="ncE-AG-MIP" secondAttribute="leading" constant="15" id="bmd-Ve-5aG"/>  | 
            |
| 478 | 333 | 
                <constraint firstItem="str-tM-QWN" firstAttribute="width" secondItem="str-tM-QWN" secondAttribute="height" id="d0r-sR-lUW"/>  | 
            
| 479 | 
                - <constraint firstItem="MsN-4R-lt2" firstAttribute="trailing" secondItem="iwc-4j-TRS" secondAttribute="trailing" id="gas-t9-dV6"/>  | 
            |
| 334 | 
                + <constraint firstAttribute="bottom" secondItem="iwc-4j-TRS" secondAttribute="bottom" id="ggt-ZE-bzP"/>  | 
            |
| 480 | 335 | 
                <constraint firstItem="u6l-UB-FoK" firstAttribute="leading" secondItem="str-tM-QWN" secondAttribute="trailing" constant="10" id="hIT-CX-JbS"/>  | 
            
| 481 | 336 | 
                <constraint firstItem="u6l-UB-FoK" firstAttribute="top" secondItem="str-tM-QWN" secondAttribute="top" id="pca-XM-Z1U"/>  | 
            
| 482 | 
                - <constraint firstItem="iwc-4j-TRS" firstAttribute="leading" secondItem="u6l-UB-FoK" secondAttribute="leading" id="rlX-um-t0a"/>  | 
            |
| 337 | 
                + <constraint firstAttribute="trailing" secondItem="MsN-4R-lt2" secondAttribute="trailing" constant="10" id="rmu-5a-Rld"/>  | 
            |
| 483 | 338 | 
                <constraint firstItem="str-tM-QWN" firstAttribute="leading" secondItem="ncE-AG-MIP" secondAttribute="leading" constant="15" id="ucZ-2U-sZg"/>  | 
            
| 484 | 339 | 
                <constraint firstItem="str-tM-QWN" firstAttribute="top" secondItem="ncE-AG-MIP" secondAttribute="top" constant="10" id="xc5-Fo-t4y"/>  | 
            
| 485 | 340 | 
                </constraints>  | 
            
                @@ -492,34 +347,42 @@  | 
            ||
| 492 | 347 | 
                </connections>  | 
            
| 493 | 348 | 
                </tableViewCell>  | 
            
| 494 | 349 | 
                </prototypes>  | 
            
| 495 | 
                - <connections>  | 
            |
| 496 | 
                - <outlet property="dataSource" destination="qsT-Pc-Bhh" id="Ftm-VU-vAa"/>  | 
            |
| 497 | 
                - <outlet property="delegate" destination="qsT-Pc-Bhh" id="Aej-45-W3l"/>  | 
            |
| 498 | 
                - </connections>  | 
            |
| 499 | 350 | 
                </tableView>  | 
            
| 500 | 
                - <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="lID-7p-0oW">  | 
            |
| 501 | 
                - <rect key="frame" x="-70.5" y="430" width="516" height="192"/>  | 
            |
| 351 | 
                + <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="lID-7p-0oW" userLabel="button group">  | 
            |
| 352 | 
                + <rect key="frame" x="46.5" y="859" width="282" height="96"/>  | 
            |
| 502 | 353 | 
                <subviews>  | 
            
| 503 | 
                - <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Tvg-6N-vtJ" userLabel="thumbup">  | 
            |
| 504 | 
                - <rect key="frame" x="162" y="0.0" width="192" height="192"/>  | 
            |
| 354 | 
                + <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="0wu-p1-ehU" userLabel="mes">  | 
            |
| 355 | 
                + <rect key="frame" x="0.0" y="13.5" width="69" height="69"/>  | 
            |
| 505 | 356 | 
                <color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>  | 
            
| 506 | 
                - <state key="normal" image="Oval 491"/>  | 
            |
| 357 | 
                + <constraints>  | 
            |
| 358 | 
                + <constraint firstAttribute="width" constant="69" id="Kl9-19-ofx"/>  | 
            |
| 359 | 
                + <constraint firstAttribute="height" constant="69" id="NE5-HG-g9l"/>  | 
            |
| 360 | 
                + </constraints>  | 
            |
| 361 | 
                + <state key="normal" image="BTN-comment"/>  | 
            |
| 507 | 362 | 
                <connections>  | 
            
| 508 | 
                - <action selector="zan" destination="qsT-Pc-Bhh" eventType="touchUpInside" id="m0i-Im-CcG"/>  | 
            |
| 363 | 
                + <action selector="comment" destination="qsT-Pc-Bhh" eventType="touchUpInside" id="CAa-E8-57D"/>  | 
            |
| 509 | 364 | 
                </connections>  | 
            
| 510 | 365 | 
                </button>  | 
            
| 511 | 
                - <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="0wu-p1-ehU" userLabel="mes">  | 
            |
| 512 | 
                - <rect key="frame" x="0.0" y="27" width="138" height="138"/>  | 
            |
| 366 | 
                + <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Tvg-6N-vtJ" userLabel="thumbup">  | 
            |
| 367 | 
                + <rect key="frame" x="93" y="0.0" width="96" height="96"/>  | 
            |
| 513 | 368 | 
                <color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>  | 
            
| 514 | 
                - <state key="normal" image="BTN-评论"/>  | 
            |
| 369 | 
                + <constraints>  | 
            |
| 370 | 
                + <constraint firstAttribute="height" constant="96" id="pQ4-9p-4wb"/>  | 
            |
| 371 | 
                + <constraint firstAttribute="width" constant="96" id="uaf-UW-oXr"/>  | 
            |
| 372 | 
                + </constraints>  | 
            |
| 373 | 
                + <state key="normal" image="BTN-thumbup"/>  | 
            |
| 515 | 374 | 
                <connections>  | 
            
| 516 | 
                - <action selector="comment" destination="qsT-Pc-Bhh" eventType="touchUpInside" id="CAa-E8-57D"/>  | 
            |
| 375 | 
                + <action selector="thumbup" destination="qsT-Pc-Bhh" eventType="touchUpInside" id="yGL-Ix-DyZ"/>  | 
            |
| 517 | 376 | 
                </connections>  | 
            
| 518 | 377 | 
                </button>  | 
            
| 519 | 378 | 
                <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="BWu-RT-ZEQ" userLabel="share">  | 
            
| 520 | 
                - <rect key="frame" x="378" y="27" width="138" height="138"/>  | 
            |
| 379 | 
                + <rect key="frame" x="213" y="13.5" width="69" height="69"/>  | 
            |
| 521 | 380 | 
                <color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>  | 
            
| 522 | 
                - <state key="normal" image="BTN-分享"/>  | 
            |
| 381 | 
                + <constraints>  | 
            |
| 382 | 
                + <constraint firstAttribute="width" constant="69" id="EcS-81-GGx"/>  | 
            |
| 383 | 
                + <constraint firstAttribute="height" constant="69" id="Mpf-VI-Pej"/>  | 
            |
| 384 | 
                + </constraints>  | 
            |
| 385 | 
                + <state key="normal" image="BTN-share"/>  | 
            |
| 523 | 386 | 
                <connections>  | 
            
| 524 | 387 | 
                <action selector="share" destination="qsT-Pc-Bhh" eventType="touchUpInside" id="ai8-KT-pxy"/>  | 
            
| 525 | 388 | 
                </connections>  | 
            
                @@ -538,8 +401,8 @@  | 
            ||
| 538 | 401 | 
                <constraint firstItem="BWu-RT-ZEQ" firstAttribute="centerY" secondItem="Tvg-6N-vtJ" secondAttribute="centerY" id="yEr-l3-Y6R"/>  | 
            
| 539 | 402 | 
                </constraints>  | 
            
| 540 | 403 | 
                </view>  | 
            
| 541 | 
                - <view hidden="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="M7B-fx-M7f">  | 
            |
| 542 | 
                - <rect key="frame" x="0.0" y="611" width="375" height="56"/>  | 
            |
| 404 | 
                + <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="M7B-fx-M7f">  | 
            |
| 405 | 
                + <rect key="frame" x="0.0" y="1000" width="375" height="56"/>  | 
            |
| 543 | 406 | 
                <subviews>  | 
            
| 544 | 407 | 
                <textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="我也说一句..." textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="1va-ae-Juh">  | 
            
| 545 | 408 | 
                <rect key="frame" x="12" y="10" width="285" height="36"/>  | 
            
                @@ -558,25 +421,15 @@  | 
            ||
| 558 | 421 | 
                </userDefinedRuntimeAttribute>  | 
            
| 559 | 422 | 
                </userDefinedRuntimeAttributes>  | 
            
| 560 | 423 | 
                </textField>  | 
            
| 561 | 
                - <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="oef-gW-sEK">  | 
            |
| 424 | 
                + <button opaque="NO" contentMode="scaleToFill" enabled="NO" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="oef-gW-sEK">  | 
            |
| 562 | 425 | 
                <rect key="frame" x="303" y="10" width="60" height="36"/>  | 
            
| 426 | 
                + <color key="backgroundColor" red="0.9995151162147522" green="0.16799759864807129" blue="0.24112263321876526" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>  | 
            |
| 563 | 427 | 
                <constraints>  | 
            
| 564 | 428 | 
                <constraint firstAttribute="width" constant="60" id="lDb-Za-vrb"/>  | 
            
| 565 | 429 | 
                </constraints>  | 
            
| 566 | 430 | 
                <state key="normal" title="发表">  | 
            
| 567 | 431 | 
                <color key="titleColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>  | 
            
| 568 | 432 | 
                </state>  | 
            
| 569 | 
                - <userDefinedRuntimeAttributes>  | 
            |
| 570 | 
                - <userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">  | 
            |
| 571 | 
                - <real key="value" value="4"/>  | 
            |
| 572 | 
                - </userDefinedRuntimeAttribute>  | 
            |
| 573 | 
                - <userDefinedRuntimeAttribute type="color" keyPath="normalStatusBackgroundColor">  | 
            |
| 574 | 
                - <color key="value" red="0.98431372549999996" green="0.31372549020000001" blue="0.31372549020000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>  | 
            |
| 575 | 
                - </userDefinedRuntimeAttribute>  | 
            |
| 576 | 
                - <userDefinedRuntimeAttribute type="color" keyPath="pressedStatusBackgroundColor">  | 
            |
| 577 | 
                - <color key="value" red="0.98431372549999996" green="0.31372549020000001" blue="0.31372549020000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>  | 
            |
| 578 | 
                - </userDefinedRuntimeAttribute>  | 
            |
| 579 | 
                - </userDefinedRuntimeAttributes>  | 
            |
| 580 | 433 | 
                <connections>  | 
            
| 581 | 434 | 
                <action selector="sendComment" destination="qsT-Pc-Bhh" eventType="touchUpInside" id="utb-Y9-GCy"/>  | 
            
| 582 | 435 | 
                </connections>  | 
            
                @@ -602,38 +455,37 @@  | 
            ||
| 602 | 455 | 
                </userDefinedRuntimeAttributes>  | 
            
| 603 | 456 | 
                </view>  | 
            
| 604 | 457 | 
                <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="n3n-4c-ZrJ">  | 
            
| 605 | 
                - <rect key="frame" x="0.0" y="619" width="375" height="48"/>  | 
            |
| 458 | 
                + <rect key="frame" x="0.0" y="952" width="375" height="48"/>  | 
            |
| 606 | 459 | 
                <subviews>  | 
            
| 607 | 460 | 
                <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="lCw-zE-NnH">  | 
            
| 608 | 461 | 
                <rect key="frame" x="0.0" y="0.0" width="375" height="48"/>  | 
            
| 609 | 462 | 
                <subviews>  | 
            
| 610 | 
                - <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="IpC-PG-FTb">  | 
            |
| 611 | 
                - <rect key="frame" x="0.0" y="0.0" width="375" height="48"/>  | 
            |
| 612 | 
                - <state key="normal" backgroundImage="去除水印"/>  | 
            |
| 613 | 
                - <connections>  | 
            |
| 614 | 
                - <action selector="waterMarkPay:" destination="qsT-Pc-Bhh" eventType="touchUpInside" id="Jms-KW-CI9"/>  | 
            |
| 615 | 
                - </connections>  | 
            |
| 616 | 
                - </button>  | 
            |
| 617 | 463 | 
                <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="购买-去水印" translatesAutoresizingMaskIntoConstraints="NO" id="pvN-rn-4Jn">  | 
            
| 618 | 
                - <rect key="frame" x="99.5" y="-24" width="96" height="96"/>  | 
            |
| 464 | 
                + <rect key="frame" x="123.5" y="0.0" width="48" height="48"/>  | 
            |
| 465 | 
                + <constraints>  | 
            |
| 466 | 
                + <constraint firstAttribute="height" constant="48" id="2VC-Nk-MXl"/>  | 
            |
| 467 | 
                + <constraint firstAttribute="width" constant="48" id="RbZ-dr-qL8"/>  | 
            |
| 468 | 
                + </constraints>  | 
            |
| 619 | 469 | 
                </imageView>  | 
            
| 620 | 470 | 
                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="去除水印" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Xot-0B-lcT">  | 
            
| 621 | 
                - <rect key="frame" x="200.5" y="15" width="62" height="18"/>  | 
            |
| 471 | 
                + <rect key="frame" x="176.5" y="15" width="62" height="18"/>  | 
            |
| 622 | 472 | 
                <fontDescription key="fontDescription" type="boldSystem" pointSize="15"/>  | 
            
| 623 | 473 | 
                <color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>  | 
            
| 624 | 474 | 
                <nil key="highlightedColor"/>  | 
            
| 625 | 475 | 
                </label>  | 
            
| 626 | 476 | 
                </subviews>  | 
            
| 477 | 
                + <accessibility key="accessibilityConfiguration">  | 
            |
| 478 | 
                + <accessibilityTraits key="traits" image="YES"/>  | 
            |
| 479 | 
                + </accessibility>  | 
            |
| 627 | 480 | 
                <constraints>  | 
            
| 628 | 
                - <constraint firstItem="IpC-PG-FTb" firstAttribute="leading" secondItem="lCw-zE-NnH" secondAttribute="leading" id="AI8-0A-5NM"/>  | 
            |
| 629 | 481 | 
                <constraint firstItem="pvN-rn-4Jn" firstAttribute="centerY" secondItem="lCw-zE-NnH" secondAttribute="centerY" id="IiE-3R-qra"/>  | 
            
| 630 | 
                - <constraint firstAttribute="trailing" secondItem="IpC-PG-FTb" secondAttribute="trailing" id="JXk-xw-Ijl"/>  | 
            |
| 631 | 482 | 
                <constraint firstItem="Xot-0B-lcT" firstAttribute="leading" secondItem="pvN-rn-4Jn" secondAttribute="trailing" constant="5" id="iEp-95-h2T"/>  | 
            
| 632 | 483 | 
                <constraint firstItem="pvN-rn-4Jn" firstAttribute="centerX" secondItem="lCw-zE-NnH" secondAttribute="centerX" constant="-40" id="ldO-mF-P0P"/>  | 
            
| 633 | 
                - <constraint firstAttribute="bottom" secondItem="IpC-PG-FTb" secondAttribute="bottom" id="w9Z-mh-Lbw"/>  | 
            |
| 634 | 
                - <constraint firstItem="IpC-PG-FTb" firstAttribute="top" secondItem="lCw-zE-NnH" secondAttribute="top" id="wZx-uT-kRL"/>  | 
            |
| 635 | 484 | 
                <constraint firstItem="Xot-0B-lcT" firstAttribute="centerY" secondItem="pvN-rn-4Jn" secondAttribute="centerY" id="z6Y-h0-ffK"/>  | 
            
| 636 | 485 | 
                </constraints>  | 
            
| 486 | 
                + <connections>  | 
            |
| 487 | 
                + <outletCollection property="gestureRecognizers" destination="thN-TP-atT" appends="YES" id="gKW-D0-5pd"/>  | 
            |
| 488 | 
                + </connections>  | 
            |
| 637 | 489 | 
                </view>  | 
            
| 638 | 490 | 
                </subviews>  | 
            
| 639 | 491 | 
                <constraints>  | 
            
                @@ -648,54 +500,64 @@  | 
            ||
| 648 | 500 | 
                <color key="backgroundColor" red="0.94117647059999998" green="0.94117647059999998" blue="0.94117647059999998" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>  | 
            
| 649 | 501 | 
                <gestureRecognizers/>  | 
            
| 650 | 502 | 
                <constraints>  | 
            
| 651 | 
                - <constraint firstItem="9RM-c8-CL6" firstAttribute="top" secondItem="BJb-h6-o9s" secondAttribute="bottom" id="73f-0Y-3Vq"/>  | 
            |
| 652 | 
                - <constraint firstItem="9RM-c8-CL6" firstAttribute="top" secondItem="lID-7p-0oW" secondAttribute="bottom" constant="45" id="8XF-qX-tug"/>  | 
            |
| 653 | 
                - <constraint firstAttribute="trailing" secondItem="BJb-h6-o9s" secondAttribute="trailing" id="FVI-fa-ovF"/>  | 
            |
| 654 | 
                - <constraint firstAttribute="bottom" secondItem="M7B-fx-M7f" secondAttribute="bottom" id="HPO-e8-4k2"/>  | 
            |
| 655 | 
                - <constraint firstItem="BJb-h6-o9s" firstAttribute="leading" secondItem="DXj-L8-o9b" secondAttribute="leading" id="LUw-LA-s32"/>  | 
            |
| 656 | 
                - <constraint firstAttribute="trailing" secondItem="M7B-fx-M7f" secondAttribute="trailing" id="N1J-SK-PaC"/>  | 
            |
| 657 | 
                - <constraint firstItem="9RM-c8-CL6" firstAttribute="top" secondItem="n3n-4c-ZrJ" secondAttribute="bottom" id="WmR-iX-rxE"/>  | 
            |
| 658 | 
                - <constraint firstItem="lID-7p-0oW" firstAttribute="centerX" secondItem="DXj-L8-o9b" secondAttribute="centerX" id="X50-n0-wZy"/>  | 
            |
| 659 | 
                - <constraint firstItem="BJb-h6-o9s" firstAttribute="top" secondItem="aUY-hC-XIK" secondAttribute="bottom" id="YxH-gE-R4v"/>  | 
            |
| 660 | 
                - <constraint firstAttribute="trailing" secondItem="n3n-4c-ZrJ" secondAttribute="trailing" id="c7G-xk-PsT"/>  | 
            |
| 661 | 
                - <constraint firstItem="n3n-4c-ZrJ" firstAttribute="leading" secondItem="DXj-L8-o9b" secondAttribute="leading" id="cYR-vc-dTi"/>  | 
            |
| 662 | 
                - <constraint firstItem="M7B-fx-M7f" firstAttribute="leading" secondItem="DXj-L8-o9b" secondAttribute="leading" id="svX-zh-yc8"/>  | 
            |
| 503 | 
                + <constraint firstItem="fD2-Ow-gtt" firstAttribute="leading" secondItem="9gv-8b-ehH" secondAttribute="leading" id="05m-kg-yB6"/>  | 
            |
| 504 | 
                + <constraint firstItem="9gv-8b-ehH" firstAttribute="bottom" secondItem="lID-7p-0oW" secondAttribute="bottom" constant="45" id="8XF-qX-tug"/>  | 
            |
| 505 | 
                + <constraint firstAttribute="bottom" secondItem="M7B-fx-M7f" secondAttribute="bottom" constant="-56" id="HPO-e8-4k2"/>  | 
            |
| 506 | 
                + <constraint firstItem="fD2-Ow-gtt" firstAttribute="top" secondItem="9gv-8b-ehH" secondAttribute="top" id="IeE-A7-ZV9"/>  | 
            |
| 507 | 
                + <constraint firstItem="9gv-8b-ehH" firstAttribute="trailing" secondItem="M7B-fx-M7f" secondAttribute="trailing" id="N1J-SK-PaC"/>  | 
            |
| 508 | 
                + <constraint firstAttribute="bottom" secondItem="n3n-4c-ZrJ" secondAttribute="bottom" id="WmR-iX-rxE"/>  | 
            |
| 509 | 
                + <constraint firstItem="lID-7p-0oW" firstAttribute="centerX" secondItem="9gv-8b-ehH" secondAttribute="centerX" id="X50-n0-wZy"/>  | 
            |
| 510 | 
                + <constraint firstAttribute="bottom" secondItem="fD2-Ow-gtt" secondAttribute="bottom" id="XB5-IP-h70"/>  | 
            |
| 511 | 
                + <constraint firstItem="9gv-8b-ehH" firstAttribute="trailing" secondItem="n3n-4c-ZrJ" secondAttribute="trailing" id="c7G-xk-PsT"/>  | 
            |
| 512 | 
                + <constraint firstItem="n3n-4c-ZrJ" firstAttribute="leading" secondItem="9gv-8b-ehH" secondAttribute="leading" id="cYR-vc-dTi"/>  | 
            |
| 513 | 
                + <constraint firstItem="9gv-8b-ehH" firstAttribute="trailing" secondItem="fD2-Ow-gtt" secondAttribute="trailing" id="riO-3O-KZ0"/>  | 
            |
| 514 | 
                + <constraint firstItem="M7B-fx-M7f" firstAttribute="leading" secondItem="9gv-8b-ehH" secondAttribute="leading" id="svX-zh-yc8"/>  | 
            |
| 663 | 515 | 
                </constraints>  | 
            
| 664 | 
                - <connections>  | 
            |
| 665 | 
                - <outletCollection property="gestureRecognizers" destination="thN-TP-atT" appends="YES" id="fm4-zR-Gbm"/>  | 
            |
| 666 | 
                - </connections>  | 
            |
| 516 | 
                + <viewLayoutGuide key="safeArea" id="9gv-8b-ehH"/>  | 
            |
| 667 | 517 | 
                </view>  | 
            
| 518 | 
                + <size key="freeformSize" width="375" height="1000"/>  | 
            |
| 668 | 519 | 
                <connections>  | 
            
| 669 | 520 | 
                <outlet property="buyView" destination="n3n-4c-ZrJ" id="SXL-nK-eIX"/>  | 
            
| 521 | 
                + <outlet property="commentCount" destination="cuT-s1-NnA" id="m50-cn-Kcn"/>  | 
            |
| 522 | 
                + <outlet property="commentEditYConstraint" destination="HPO-e8-4k2" id="tfy-Rg-aiz"/>  | 
            |
| 523 | 
                + <outlet property="commentEditingView" destination="M7B-fx-M7f" id="ZRf-mw-WVD"/>  | 
            |
| 670 | 524 | 
                <outlet property="commentHeight" destination="HPO-e8-4k2" id="gpG-te-dKf"/>  | 
            
| 525 | 
                + <outlet property="commentTableView" destination="fD2-Ow-gtt" id="jog-WM-p44"/>  | 
            |
| 671 | 526 | 
                <outlet property="commentTextField" destination="1va-ae-Juh" id="TpO-kE-PhT"/>  | 
            
| 672 | 
                - <outlet property="commentView" destination="M7B-fx-M7f" id="c0Q-vg-7C9"/>  | 
            |
| 527 | 
                + <outlet property="enterGroupView" destination="gSr-Cm-y1W" id="bNT-Z4-eOG"/>  | 
            |
| 528 | 
                + <outlet property="groupAvatar" destination="nng-M9-7cj" id="Y42-Tc-QnV"/>  | 
            |
| 529 | 
                + <outlet property="groupName" destination="XM7-FX-tOk" id="ifP-h1-72j"/>  | 
            |
| 530 | 
                + <outlet property="photoCollectionView" destination="dtf-M8-otl" id="VlY-wa-ekc"/>  | 
            |
| 531 | 
                + <outlet property="photoTime" destination="QpI-Mp-URP" id="rJM-TG-fZW"/>  | 
            |
| 673 | 532 | 
                <outlet property="sendBtn" destination="oef-gW-sEK" id="3RV-uD-3q1"/>  | 
            
| 674 | 
                - <outlet property="shuiyinImage" destination="pvN-rn-4Jn" id="SOk-vE-uCT"/>  | 
            |
| 675 | 
                - <outlet property="shuiyinLabel" destination="Xot-0B-lcT" id="eWR-Rv-Fzl"/>  | 
            |
| 676 | 
                - <outlet property="tableView" destination="BJb-h6-o9s" id="XS2-bS-jiH"/>  | 
            |
| 677 | 
                - <outlet property="thumbupView" destination="lID-7p-0oW" id="nBh-5u-Utm"/>  | 
            |
| 678 | 
                - <outlet property="waterMarkView" destination="lCw-zE-NnH" id="CPm-lw-FQT"/>  | 
            |
| 533 | 
                + <outlet property="thumbupCount" destination="h88-PP-cvG" id="hwu-eb-a1J"/>  | 
            |
| 534 | 
                + <outlet property="thumbupView" destination="Zde-8U-5Bl" id="ceB-lf-AhY"/>  | 
            |
| 535 | 
                + <outlet property="thumbupViewHeightConstraint" destination="fc8-6l-lEC" id="E8M-of-NHC"/>  | 
            |
| 536 | 
                + <outlet property="userAvatar" destination="Zj6-ve-uzJ" id="3Un-We-QLK"/>  | 
            |
| 537 | 
                + <outlet property="userName" destination="jmc-9F-Uzr" id="1Z5-wc-83i"/>  | 
            |
| 538 | 
                + <outlet property="waterMarkImage" destination="pvN-rn-4Jn" id="TaO-CX-590"/>  | 
            |
| 539 | 
                + <outlet property="waterMarkLabel" destination="Xot-0B-lcT" id="Jok-hr-Eeb"/>  | 
            |
| 540 | 
                + <outlet property="waterMarkView" destination="lCw-zE-NnH" id="z8i-gh-ZRG"/>  | 
            |
| 679 | 541 | 
                </connections>  | 
            
| 680 | 542 | 
                </viewController>  | 
            
| 681 | 543 | 
                <placeholder placeholderIdentifier="IBFirstResponder" id="MFn-pn-5Jb" userLabel="First Responder" sceneMemberID="firstResponder"/>  | 
            
| 682 | 
                - <tapGestureRecognizer id="thN-TP-atT">  | 
            |
| 544 | 
                + <tapGestureRecognizer id="thN-TP-atT" userLabel="purchaseGestureRecognizer">  | 
            |
| 683 | 545 | 
                <connections>  | 
            
| 684 | 
                - <action selector="ReturnKeyboard:" destination="qsT-Pc-Bhh" id="uVf-UL-SuP"/>  | 
            |
| 685 | 
                - <outlet property="delegate" destination="qsT-Pc-Bhh" id="vFS-jJ-MlO"/>  | 
            |
| 546 | 
                + <action selector="purchase:" destination="qsT-Pc-Bhh" id="qjs-Ot-XwA"/>  | 
            |
| 547 | 
                + </connections>  | 
            |
| 548 | 
                + </tapGestureRecognizer>  | 
            |
| 549 | 
                + <tapGestureRecognizer id="EHE-XX-kIE" userLabel="enterGroupGestureRecognizer">  | 
            |
| 550 | 
                + <connections>  | 
            |
| 551 | 
                + <action selector="enterGroup:" destination="qsT-Pc-Bhh" id="dZE-ok-iUM"/>  | 
            |
| 686 | 552 | 
                </connections>  | 
            
| 687 | 553 | 
                </tapGestureRecognizer>  | 
            
| 688 | 554 | 
                </objects>  | 
            
| 689 | 
                - <point key="canvasLocation" x="-1927.2" y="1267.0164917541231"/>  | 
            |
| 555 | 
                + <point key="canvasLocation" x="-1452" y="1137.9310344827586"/>  | 
            |
| 690 | 556 | 
                </scene>  | 
            
| 691 | 557 | 
                <!--ShareController-->  | 
            
| 692 | 558 | 
                <scene sceneID="UTe-rv-qoO">  | 
            
| 693 | 559 | 
                <objects>  | 
            
| 694 | 560 | 
                <viewController storyboardIdentifier="ShareController" automaticallyAdjustsScrollViewInsets="NO" id="KnW-jg-4H5" userLabel="ShareController" customClass="ShareController" customModule="Paiai_iOS" customModuleProvider="target" sceneMemberID="viewController">  | 
            
| 695 | 
                - <layoutGuides>  | 
            |
| 696 | 
                - <viewControllerLayoutGuide type="top" id="hPQ-yS-v0d"/>  | 
            |
| 697 | 
                - <viewControllerLayoutGuide type="bottom" id="xwf-Eg-SuC"/>  | 
            |
| 698 | 
                - </layoutGuides>  | 
            |
| 699 | 561 | 
                <view key="view" contentMode="scaleToFill" id="rN5-Zb-vwm">  | 
            
| 700 | 562 | 
                <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>  | 
            
| 701 | 563 | 
                <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>  | 
            
                @@ -795,10 +657,11 @@  | 
            ||
| 795 | 657 | 
                </subviews>  | 
            
| 796 | 658 | 
                <gestureRecognizers/>  | 
            
| 797 | 659 | 
                <constraints>  | 
            
| 798 | 
                - <constraint firstItem="xUW-ue-yp5" firstAttribute="leading" secondItem="rN5-Zb-vwm" secondAttribute="leading" id="Afy-jR-Jec"/>  | 
            |
| 799 | 
                - <constraint firstItem="xwf-Eg-SuC" firstAttribute="top" secondItem="xUW-ue-yp5" secondAttribute="bottom" constant="127" id="hco-RD-Kle"/>  | 
            |
| 800 | 
                - <constraint firstAttribute="trailing" secondItem="xUW-ue-yp5" secondAttribute="trailing" id="lAd-Wf-RcE"/>  | 
            |
| 660 | 
                + <constraint firstItem="xUW-ue-yp5" firstAttribute="leading" secondItem="C6P-7J-fWs" secondAttribute="leading" id="Afy-jR-Jec"/>  | 
            |
| 661 | 
                + <constraint firstItem="C6P-7J-fWs" firstAttribute="bottom" secondItem="xUW-ue-yp5" secondAttribute="bottom" constant="127" id="hco-RD-Kle"/>  | 
            |
| 662 | 
                + <constraint firstItem="C6P-7J-fWs" firstAttribute="trailing" secondItem="xUW-ue-yp5" secondAttribute="trailing" id="lAd-Wf-RcE"/>  | 
            |
| 801 | 663 | 
                </constraints>  | 
            
| 664 | 
                + <viewLayoutGuide key="safeArea" id="C6P-7J-fWs"/>  | 
            |
| 802 | 665 | 
                </view>  | 
            
| 803 | 666 | 
                <connections>  | 
            
| 804 | 667 | 
                <outlet property="shareView" destination="xUW-ue-yp5" id="I5g-Zk-9uW"/>  | 
            
                @@ -806,22 +669,18 @@  | 
            ||
| 806 | 669 | 
                </viewController>  | 
            
| 807 | 670 | 
                <placeholder placeholderIdentifier="IBFirstResponder" id="9LO-35-FRH" userLabel="First Responder" sceneMemberID="firstResponder"/>  | 
            
| 808 | 671 | 
                </objects>  | 
            
| 809 | 
                - <point key="canvasLocation" x="649.60000000000002" y="1430.2848575712146"/>  | 
            |
| 672 | 
                + <point key="canvasLocation" x="-513" y="1287"/>  | 
            |
| 810 | 673 | 
                </scene>  | 
            
| 811 | 
                - <!--ShowFullPicController-->  | 
            |
| 674 | 
                + <!--PhotoPreviewViewController-->  | 
            |
| 812 | 675 | 
                <scene sceneID="yhk-2u-fiu">  | 
            
| 813 | 676 | 
                <objects>  | 
            
| 814 | 
                - <viewController storyboardIdentifier="ShowFullPicController" automaticallyAdjustsScrollViewInsets="NO" id="p3y-A2-QU1" userLabel="ShowFullPicController" customClass="ShowFullPicController" customModule="PaiAi" sceneMemberID="viewController">  | 
            |
| 815 | 
                - <layoutGuides>  | 
            |
| 816 | 
                - <viewControllerLayoutGuide type="top" id="LdU-do-COB"/>  | 
            |
| 817 | 
                - <viewControllerLayoutGuide type="bottom" id="uHN-Ad-PoZ"/>  | 
            |
| 818 | 
                - </layoutGuides>  | 
            |
| 677 | 
                + <viewController storyboardIdentifier="PhotoPreviewViewController" automaticallyAdjustsScrollViewInsets="NO" id="p3y-A2-QU1" userLabel="PhotoPreviewViewController" customClass="PhotoPreviewViewController" customModule="Paiai_iOS" customModuleProvider="target" sceneMemberID="viewController">  | 
            |
| 819 | 678 | 
                <view key="view" contentMode="scaleToFill" id="MdC-Fu-zFL">  | 
            
| 820 | 679 | 
                <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>  | 
            
| 821 | 680 | 
                <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>  | 
            
| 822 | 681 | 
                <subviews>  | 
            
| 823 | 
                - <collectionView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" pagingEnabled="YES" showsHorizontalScrollIndicator="NO" showsVerticalScrollIndicator="NO" indicatorStyle="white" dataMode="prototypes" translatesAutoresizingMaskIntoConstraints="NO" id="cvI-jg-TrD">  | 
            |
| 824 | 
                - <rect key="frame" x="0.0" y="20" width="395" height="647"/>  | 
            |
| 682 | 
                + <collectionView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" pagingEnabled="YES" showsHorizontalScrollIndicator="NO" showsVerticalScrollIndicator="NO" indicatorStyle="white" dataMode="prototypes" prefetchingEnabled="NO" translatesAutoresizingMaskIntoConstraints="NO" id="cvI-jg-TrD">  | 
            |
| 683 | 
                + <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>  | 
            |
| 825 | 684 | 
                <collectionViewFlowLayout key="collectionViewLayout" scrollDirection="horizontal" minimumLineSpacing="0.0" minimumInteritemSpacing="0.0" id="nE7-Ce-1KB">  | 
            
| 826 | 685 | 
                <size key="itemSize" width="237.5" height="357"/>  | 
            
| 827 | 686 | 
                <size key="headerReferenceSize" width="0.0" height="0.0"/>  | 
            
                @@ -830,7 +689,7 @@  | 
            ||
| 830 | 689 | 
                </collectionViewFlowLayout>  | 
            
| 831 | 690 | 
                <cells>  | 
            
| 832 | 691 | 
                <collectionViewCell opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" reuseIdentifier="imageCell" id="PAU-eQ-c9k" customClass="ImageCell" customModule="Paiai_iOS" customModuleProvider="target">  | 
            
| 833 | 
                - <rect key="frame" x="0.0" y="145" width="237.5" height="357"/>  | 
            |
| 692 | 
                + <rect key="frame" x="0.0" y="155" width="237.5" height="357"/>  | 
            |
| 834 | 693 | 
                <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>  | 
            
| 835 | 694 | 
                <view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center">  | 
            
| 836 | 695 | 
                <rect key="frame" x="0.0" y="0.0" width="237.5" height="357"/>  | 
            
                @@ -856,35 +715,31 @@  | 
            ||
| 856 | 715 | 
                </connections>  | 
            
| 857 | 716 | 
                </collectionViewCell>  | 
            
| 858 | 717 | 
                </cells>  | 
            
| 859 | 
                - <connections>  | 
            |
| 860 | 
                - <outlet property="dataSource" destination="p3y-A2-QU1" id="gOQ-91-JoU"/>  | 
            |
| 861 | 
                - <outlet property="delegate" destination="p3y-A2-QU1" id="Woc-UQ-V73"/>  | 
            |
| 862 | 
                - </connections>  | 
            |
| 863 | 718 | 
                </collectionView>  | 
            
| 864 | 
                - <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="BRP-J0-WGF">  | 
            |
| 719 | 
                + <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="BRP-J0-WGF" userLabel="button group">  | 
            |
| 865 | 720 | 
                <rect key="frame" x="0.0" y="623" width="375" height="44"/>  | 
            
| 866 | 721 | 
                <subviews>  | 
            
| 867 | 
                - <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Q90-2h-mGx">  | 
            |
| 868 | 
                - <rect key="frame" x="231" y="-26" width="96" height="96"/>  | 
            |
| 869 | 
                - <state key="normal" image="大图模式-下载"/>  | 
            |
| 870 | 
                - <connections>  | 
            |
| 871 | 
                - <action selector="load" destination="p3y-A2-QU1" eventType="touchUpInside" id="tC2-9R-1be"/>  | 
            |
| 872 | 
                - </connections>  | 
            |
| 873 | 
                - </button>  | 
            |
| 874 | 
                - <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="2r6-s1-9be">  | 
            |
| 722 | 
                + <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="2r6-s1-9be" userLabel="back">  | 
            |
| 875 | 723 | 
                <rect key="frame" x="43.5" y="-26" width="96" height="96"/>  | 
            
| 876 | 
                - <state key="normal" image="back"/>  | 
            |
| 724 | 
                + <state key="normal" image="navigation-back"/>  | 
            |
| 877 | 725 | 
                <connections>  | 
            
| 878 | 726 | 
                <action selector="back" destination="p3y-A2-QU1" eventType="touchUpInside" id="xKk-c3-Iub"/>  | 
            
| 879 | 727 | 
                </connections>  | 
            
| 880 | 728 | 
                </button>  | 
            
| 881 | 
                - <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="aOC-mu-785">  | 
            |
| 729 | 
                + <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="aOC-mu-785" userLabel="rotate">  | 
            |
| 882 | 730 | 
                <rect key="frame" x="139.5" y="-26" width="96" height="96"/>  | 
            
| 883 | 
                - <state key="normal" image="旋转"/>  | 
            |
| 731 | 
                + <state key="normal" image="BTN-rotate"/>  | 
            |
| 884 | 732 | 
                <connections>  | 
            
| 885 | 733 | 
                <action selector="rotateTheImage:" destination="p3y-A2-QU1" eventType="touchUpInside" id="LiB-TG-UYL"/>  | 
            
| 886 | 734 | 
                </connections>  | 
            
| 887 | 735 | 
                </button>  | 
            
| 736 | 
                + <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Q90-2h-mGx" userLabel="download">  | 
            |
| 737 | 
                + <rect key="frame" x="231" y="-26" width="96" height="96"/>  | 
            |
| 738 | 
                + <state key="normal" image="BTN-download"/>  | 
            |
| 739 | 
                + <connections>  | 
            |
| 740 | 
                + <action selector="download:" destination="p3y-A2-QU1" eventType="touchUpInside" id="cEE-Yt-FWf"/>  | 
            |
| 741 | 
                + </connections>  | 
            |
| 742 | 
                + </button>  | 
            |
| 888 | 743 | 
                </subviews>  | 
            
| 889 | 744 | 
                <color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.5" colorSpace="custom" customColorSpace="sRGB"/>  | 
            
| 890 | 745 | 
                <constraints>  | 
            
                @@ -902,14 +757,15 @@  | 
            ||
| 902 | 757 | 
                </subviews>  | 
            
| 903 | 758 | 
                <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>  | 
            
| 904 | 759 | 
                <constraints>  | 
            
| 905 | 
                - <constraint firstItem="uHN-Ad-PoZ" firstAttribute="top" secondItem="cvI-jg-TrD" secondAttribute="bottom" id="F0H-Mg-CBe"/>  | 
            |
| 906 | 
                - <constraint firstItem="uHN-Ad-PoZ" firstAttribute="top" secondItem="BRP-J0-WGF" secondAttribute="bottom" id="HMX-tH-TKt"/>  | 
            |
| 907 | 
                - <constraint firstItem="cvI-jg-TrD" firstAttribute="top" secondItem="MdC-Fu-zFL" secondAttribute="topMargin" id="bET-rg-QJH"/>  | 
            |
| 908 | 
                - <constraint firstItem="cvI-jg-TrD" firstAttribute="leading" secondItem="MdC-Fu-zFL" secondAttribute="leading" id="bxo-Ri-B7l"/>  | 
            |
| 909 | 
                - <constraint firstAttribute="trailing" secondItem="BRP-J0-WGF" secondAttribute="trailing" id="es7-Qg-qLl"/>  | 
            |
| 910 | 
                - <constraint firstItem="BRP-J0-WGF" firstAttribute="leading" secondItem="MdC-Fu-zFL" secondAttribute="leading" id="nES-ms-zxG"/>  | 
            |
| 911 | 
                - <constraint firstAttribute="trailing" secondItem="cvI-jg-TrD" secondAttribute="trailing" constant="-20" id="y4O-SP-QE3"/>  | 
            |
| 760 | 
                + <constraint firstAttribute="bottom" secondItem="cvI-jg-TrD" secondAttribute="bottom" id="F0H-Mg-CBe"/>  | 
            |
| 761 | 
                + <constraint firstItem="pxb-BY-KAJ" firstAttribute="bottom" secondItem="BRP-J0-WGF" secondAttribute="bottom" id="HMX-tH-TKt"/>  | 
            |
| 762 | 
                + <constraint firstItem="cvI-jg-TrD" firstAttribute="top" secondItem="MdC-Fu-zFL" secondAttribute="top" id="bET-rg-QJH"/>  | 
            |
| 763 | 
                + <constraint firstItem="cvI-jg-TrD" firstAttribute="leading" secondItem="pxb-BY-KAJ" secondAttribute="leading" id="bxo-Ri-B7l"/>  | 
            |
| 764 | 
                + <constraint firstItem="pxb-BY-KAJ" firstAttribute="trailing" secondItem="BRP-J0-WGF" secondAttribute="trailing" id="es7-Qg-qLl"/>  | 
            |
| 765 | 
                + <constraint firstItem="BRP-J0-WGF" firstAttribute="leading" secondItem="pxb-BY-KAJ" secondAttribute="leading" id="nES-ms-zxG"/>  | 
            |
| 766 | 
                + <constraint firstItem="pxb-BY-KAJ" firstAttribute="trailing" secondItem="cvI-jg-TrD" secondAttribute="trailing" id="y4O-SP-QE3"/>  | 
            |
| 912 | 767 | 
                </constraints>  | 
            
| 768 | 
                + <viewLayoutGuide key="safeArea" id="pxb-BY-KAJ"/>  | 
            |
| 913 | 769 | 
                </view>  | 
            
| 914 | 770 | 
                <connections>  | 
            
| 915 | 771 | 
                <outlet property="collectionView" destination="cvI-jg-TrD" id="1eT-ax-Cma"/>  | 
            
                @@ -921,23 +777,22 @@  | 
            ||
| 921 | 777 | 
                </scene>  | 
            
| 922 | 778 | 
                </scenes>  | 
            
| 923 | 779 | 
                <resources>  | 
            
| 924 | 
                - <image name="BTN-分享" width="138" height="138"/>  | 
            |
| 925 | 
                - <image name="BTN-评论" width="138" height="138"/>  | 
            |
| 926 | 
                - <image name="Oval 491" width="192" height="192"/>  | 
            |
| 927 | 
                - <image name="back" width="36" height="72"/>  | 
            |
| 928 | 
                - <image name="icon-记录" width="36" height="36"/>  | 
            |
| 929 | 
                - <image name="icon-评论" width="36" height="36"/>  | 
            |
| 930 | 
                - <image name="icon-赞" width="36" height="36"/>  | 
            |
| 931 | 
                - <image name="list-arrow" width="16" height="16"/>  | 
            |
| 780 | 
                + <image name="BTN-comment" width="138" height="138"/>  | 
            |
| 781 | 
                + <image name="BTN-download" width="96" height="96"/>  | 
            |
| 782 | 
                + <image name="BTN-rotate" width="96" height="96"/>  | 
            |
| 783 | 
                + <image name="BTN-share" width="138" height="138"/>  | 
            |
| 784 | 
                + <image name="BTN-thumbup" width="192" height="192"/>  | 
            |
| 785 | 
                + <image name="defaultAvatar" width="240" height="240"/>  | 
            |
| 786 | 
                + <image name="icon-comment" width="36" height="36"/>  | 
            |
| 787 | 
                + <image name="icon-thumbup" width="36" height="36"/>  | 
            |
| 788 | 
                + <image name="icon-time" width="36" height="36"/>  | 
            |
| 789 | 
                + <image name="list-arrow" width="24" height="36"/>  | 
            |
| 790 | 
                + <image name="navigation-back" width="36" height="72"/>  | 
            |
| 932 | 791 | 
                <image name="分享-QQ" width="162" height="162"/>  | 
            
| 933 | 792 | 
                <image name="分享-微信好友" width="162" height="162"/>  | 
            
| 934 | 793 | 
                <image name="分享-微博" width="162" height="162"/>  | 
            
| 935 | 794 | 
                <image name="分享-朋友圈" width="162" height="162"/>  | 
            
| 936 | 
                - <image name="去除水印" width="8" height="144"/>  | 
            |
| 937 | 
                - <image name="大图模式-下载" width="96" height="96"/>  | 
            |
| 938 | 
                - <image name="旋转" width="96" height="96"/>  | 
            |
| 939 | 795 | 
                <image name="购买-去水印" width="96" height="96"/>  | 
            
| 940 | 796 | 
                <image name="进入群" width="114" height="60"/>  | 
            
| 941 | 
                - <image name="默认头像" width="80" height="80"/>  | 
            |
| 942 | 797 | 
                </resources>  | 
            
| 943 | 798 | 
                </document>  | 
            
                @@ -1,5 +1,5 @@  | 
            ||
| 1 | 1 | 
                //  | 
            
| 2 | 
                -// DetailCommentCell.swift  | 
            |
| 2 | 
                +// PhotoDetailCommentCell.swift  | 
            |
| 3 | 3 | 
                // PaiAi  | 
            
| 4 | 4 | 
                //  | 
            
| 5 | 5 | 
                // Created by zhengjianfei on 16/4/8.  | 
            
                @@ -10,7 +10,7 @@ import UIKit  | 
            ||
| 10 | 10 | 
                import PaiaiDataKit  | 
            
| 11 | 11 | 
                import PaiaiUIKit  | 
            
| 12 | 12 | 
                 | 
            
| 13 | 
                -class DetailCommentCell: UITableViewCell {
               | 
            |
| 13 | 
                +class PhotoDetailCommentCell: UITableViewCell {
               | 
            |
| 14 | 14 | 
                 | 
            
| 15 | 15 | 
                // MARK: Storyboard property  | 
            
| 16 | 16 | 
                @IBOutlet weak var headImage: UIImageView!  | 
            
                @@ -7,9 +7,57 @@  | 
            ||
| 7 | 7 | 
                //  | 
            
| 8 | 8 | 
                 | 
            
| 9 | 9 | 
                import Foundation  | 
            
| 10 | 
                +import PaiaiDataKit  | 
            |
| 11 | 
                +  | 
            |
| 12 | 
                +final class PhotoDetailCoordinator: Coordinator {
               | 
            |
| 13 | 
                + let navigationController: UINavigationController  | 
            |
| 14 | 
                + let photoDetailViewController: PhotoDetailViewController  | 
            |
| 15 | 
                + let shareListViewModel: PhotoDetailListViewModel  | 
            |
| 16 | 
                +  | 
            |
| 17 | 
                + fileprivate var coordinators = [String: Coordinator]()  | 
            |
| 18 | 
                +  | 
            |
| 19 | 
                + init(_ photoDetailVC: PhotoDetailViewController,  | 
            |
| 20 | 
                + nav: UINavigationController,  | 
            |
| 21 | 
                + viewModel: PhotoDetailViewModel,  | 
            |
| 22 | 
                +         listViewModel: PhotoDetailListViewModel) {
               | 
            |
| 23 | 
                + photoDetailViewController = photoDetailVC  | 
            |
| 24 | 
                + shareListViewModel = listViewModel  | 
            |
| 25 | 
                + navigationController = nav  | 
            |
| 26 | 
                + photoDetailViewController.listViewModel = shareListViewModel  | 
            |
| 27 | 
                + photoDetailViewController.viewModel = viewModel  | 
            |
| 28 | 
                +  | 
            |
| 29 | 
                + viewModel.delegate = self  | 
            |
| 30 | 
                + shareListViewModel.synchronization = viewModel  | 
            |
| 31 | 
                + shareListViewModel.delegate = self  | 
            |
| 32 | 
                + }  | 
            |
| 33 | 
                +  | 
            |
| 34 | 
                +    func start() {
               | 
            |
| 35 | 
                +  | 
            |
| 36 | 
                + }  | 
            |
| 37 | 
                +}  | 
            |
| 38 | 
                +  | 
            |
| 39 | 
                +extension PhotoDetailCoordinator: PhotoDetailViewModelDelegate {
               | 
            |
| 40 | 
                +    func navigateToGroup(_ item: GroupItem) {
               | 
            |
| 41 | 
                + let vc = GroupViewController.instantiate()  | 
            |
| 42 | 
                + vc.viewModel = GroupViewModel(groupItem: item)  | 
            |
| 43 | 
                + let coordinator = GroupCoordinator(vc,  | 
            |
| 44 | 
                + navigationController: navigationController)  | 
            |
| 45 | 
                + coordinators["group"] = coordinator  | 
            |
| 46 | 
                +  | 
            |
| 47 | 
                + navigationController.pushViewController(vc)  | 
            |
| 48 | 
                + }  | 
            |
| 49 | 
                +}  | 
            |
| 50 | 
                +  | 
            |
| 51 | 
                +extension PhotoDetailCoordinator: PhotoDetailListViewModelDelegate {
               | 
            |
| 52 | 
                +    func didSelected() {
               | 
            |
| 53 | 
                + let vc = UIStoryboard.photoDetail.instantiateController(PhotoPreviewViewController.self)  | 
            |
| 54 | 
                + vc.viewModel = shareListViewModel  | 
            |
| 55 | 
                + navigationController.pushViewController(vc, animated: true)  | 
            |
| 56 | 
                + }  | 
            |
| 57 | 
                +}  | 
            |
| 10 | 58 | 
                 | 
            
| 11 | 59 | 
                 extension UIStoryboard {
               | 
            
| 12 | 60 | 
                     static var photoDetail: UIStoryboard {
               | 
            
| 13 | 
                - return UIStoryboard(name: "Detail", bundle: Bundle(identifier: "com.Paiai-iOS"))  | 
            |
| 61 | 
                + return UIStoryboard(name: "PhotoDetail", bundle: Bundle(identifier: "com.Paiai-iOS"))  | 
            |
| 14 | 62 | 
                }  | 
            
| 15 | 63 | 
                }  | 
            
                @@ -9,5 +9,5 @@  | 
            ||
| 9 | 9 | 
                import UIKit  | 
            
| 10 | 10 | 
                 | 
            
| 11 | 11 | 
                 class PhotoDetailImageCell: UICollectionViewCell {
               | 
            
| 12 | 
                -  | 
            |
| 12 | 
                + @IBOutlet weak var imageView: UIImageView!  | 
            |
| 13 | 13 | 
                }  | 
            
                @@ -9,6 +9,7 @@  | 
            ||
| 9 | 9 | 
                import UIKit  | 
            
| 10 | 10 | 
                import RxSwift  | 
            
| 11 | 11 | 
                import RxCocoa  | 
            
| 12 | 
                +import RxDataSources  | 
            |
| 12 | 13 | 
                import PaiaiDataKit  | 
            
| 13 | 14 | 
                import PaiaiUIKit  | 
            
| 14 | 15 | 
                 | 
            
                @@ -17,6 +18,7 @@ let kPhotographerMark = 1  | 
            ||
| 17 | 18 | 
                 | 
            
| 18 | 19 | 
                 final class PhotoDetailViewController: UIViewController {
               | 
            
| 19 | 20 | 
                 | 
            
| 21 | 
                + @IBOutlet weak var enterGroupView: UIView!  | 
            |
| 20 | 22 | 
                @IBOutlet weak var groupAvatar: UIImageView!  | 
            
| 21 | 23 | 
                @IBOutlet weak var groupName: UILabel!  | 
            
| 22 | 24 | 
                 | 
            
                @@ -30,409 +32,333 @@ final class PhotoDetailViewController: UIViewController {
               | 
            ||
| 30 | 32 | 
                @IBOutlet weak var thumbupView: UIView!  | 
            
| 31 | 33 | 
                 | 
            
| 32 | 34 | 
                @IBOutlet weak var commentCount: UILabel!  | 
            
| 33 | 
                - @IBOutlet weak var tableView: UITableView!  | 
            |
| 35 | 
                + @IBOutlet weak var commentTableView: UITableView!  | 
            |
| 34 | 36 | 
                 | 
            
| 35 | 
                - @IBOutlet weak var commentView: UIView!  | 
            |
| 37 | 
                + @IBOutlet weak var commentEditingView: UIView!  | 
            |
| 36 | 38 | 
                @IBOutlet weak var commentHeight: NSLayoutConstraint!  | 
            
| 37 | 39 | 
                @IBOutlet weak var commentTextField: UITextField!  | 
            
| 38 | 40 | 
                @IBOutlet weak var sendBtn: UIButton!  | 
            
| 39 | 41 | 
                 | 
            
| 40 | 42 | 
                @IBOutlet weak var buyView: UIView!  | 
            
| 43 | 
                + @IBOutlet weak var waterMarkView: UIView!  | 
            |
| 41 | 44 | 
                @IBOutlet weak var waterMarkImage: UIImageView!  | 
            
| 42 | 45 | 
                @IBOutlet weak var waterMarkLabel: UILabel!  | 
            
| 43 | 
                -  | 
            |
| 46 | 
                +  | 
            |
| 47 | 
                + @IBOutlet weak var thumbupViewHeightConstraint: NSLayoutConstraint!  | 
            |
| 48 | 
                + @IBOutlet weak var commentEditYConstraint: NSLayoutConstraint!  | 
            |
| 49 | 
                +  | 
            |
| 44 | 50 | 
                // MARK: data property  | 
            
| 45 | 51 | 
                var viewModel: PhotoDetailViewModel!  | 
            
| 46 | 
                - lazy var datas = [PhotoItem]()  | 
            |
| 47 | 
                - lazy var currentPhotoIndex = 0  | 
            |
| 48 | 
                - var isHiddenEnterView = false  | 
            |
| 52 | 
                + var listViewModel: PhotoDetailListViewModel!  | 
            |
| 53 | 
                +  | 
            |
| 49 | 54 | 
                let disposeBag = DisposeBag()  | 
            
| 50 | 
                - static let storyboardCtl = UIStoryboard.photoDetail.instantiateInitialViewController() as! PhotoDetailViewController  | 
            |
| 51 | 55 | 
                 | 
            
| 52 | 56 | 
                // MARK: view function  | 
            
| 53 | 57 | 
                     override func viewDidLoad() {
               | 
            
| 54 | 58 | 
                super.viewDidLoad()  | 
            
| 55 | 
                -// detailPageViewModel.tipDelegate = self  | 
            |
| 56 | 
                -// tableView.tableFooterView = UIView()  | 
            |
| 57 | 
                - configureNotification()  | 
            |
| 58 | 
                -  | 
            |
| 59 | 
                - commentTextField.rx.text  | 
            |
| 60 | 
                -                        .map {!($0?.isEmpty)!}
               | 
            |
| 61 | 
                - .bind(to: sendBtn.rx.isEnabled)  | 
            |
| 62 | 
                - .disposed(by: disposeBag)  | 
            |
| 59 | 
                + binding()  | 
            |
| 60 | 
                + setup()  | 
            |
| 61 | 
                + }  | 
            |
| 62 | 
                +  | 
            |
| 63 | 
                +    func setup() {
               | 
            |
| 64 | 
                + setupCommentTextField()  | 
            |
| 65 | 
                + setupWaterMarkView()  | 
            |
| 63 | 66 | 
                }  | 
            
| 64 | 67 | 
                 | 
            
| 65 | 68 | 
                     func setupCommentTextField() {
               | 
            
| 66 | 69 | 
                commentTextField.addLeftPadding(7)  | 
            
| 67 | 70 | 
                }  | 
            
| 71 | 
                +  | 
            |
| 72 | 
                +    func setupWaterMarkView() {
               | 
            |
| 73 | 
                +        guard let image = UIImage.PhotoDetail.purchaseBackground else { return }
               | 
            |
| 74 | 
                + waterMarkView.backgroundColor = UIColor(patternImage: image)  | 
            |
| 75 | 
                + }  | 
            |
| 68 | 76 | 
                 | 
            
| 69 | 77 | 
                     override func viewWillAppear(_ animated: Bool) {
               | 
            
| 70 | 78 | 
                super.viewWillAppear(true)  | 
            
| 71 | 
                -// titleWithbackBar = "详情"  | 
            |
| 72 | 
                - navigationController?.isNavigationBarHidden = false  | 
            |
| 73 | 
                -// refreshUI(index: currentPhotoIndex)  | 
            |
| 74 | 
                - }  | 
            |
| 75 | 
                -  | 
            |
| 76 | 
                -//    override func backToController() {
               | 
            |
| 77 | 
                -// navigationController?.popViewController(animated: true)  | 
            |
| 78 | 
                -//        if let last = navigationController?.viewControllers[(navigationController?.viewControllers.count)! - 1] as? HomeViewController {
               | 
            |
| 79 | 
                -//// last.mainViewModel.models.value = datas  | 
            |
| 80 | 
                -// }  | 
            |
| 81 | 
                -//  | 
            |
| 82 | 
                -//        if let last = navigationController?.viewControllers[(navigationController?.viewControllers.count)! - 1] as? GroupViewController {
               | 
            |
| 83 | 
                -//// last.MineGroupViewModel.models.value = datas  | 
            |
| 84 | 
                -// }  | 
            |
| 85 | 
                -// }  | 
            |
| 86 | 
                -  | 
            |
| 87 | 
                -    func configureNotification() {
               | 
            |
| 88 | 
                -        do {
               | 
            |
| 89 | 
                -//            NotificationCenter.default.rx.notification(Notification.Name(rawValue: WXPayDidFinishNotification)).asObservable().subscribe { (notification) in
               | 
            |
| 90 | 
                -// FFToastView.showLoadingToast(inView: UIApplication.shared.keyWindow!, blockSuperView: true)  | 
            |
| 91 | 
                -//                self.detailPageViewModel.handleResult(errorCode: 0, success: {[weak self](PhotoItem) in
               | 
            |
| 92 | 
                -//                    if let weakself = self {
               | 
            |
| 93 | 
                -// weakself.datas[weakself.currentPhotoIndex].murl = PhotoItem.murl  | 
            |
| 94 | 
                -// weakself.datas[weakself.currentPhotoIndex].rurl = PhotoItem.rurl  | 
            |
| 95 | 
                -//// weakself.showBuyView()  | 
            |
| 96 | 
                -// weakself.tableView.reloadRows(at: [IndexPath(item: 0, section: 1)], with: .none)  | 
            |
| 97 | 
                -// let fullPicCtl = UIStoryboard.detailBoard.instantiateController(ShowFullPicController.self)  | 
            |
| 98 | 
                -// fullPicCtl.datas = weakself.datas  | 
            |
| 99 | 
                -// fullPicCtl.currentPhotoIndex = weakself.currentPhotoIndex  | 
            |
| 100 | 
                -// fullPicCtl.showNomark = weakself.detailPageViewModel.watermarkPrice != -1  | 
            |
| 101 | 
                -// fullPicCtl.showHD = weakself.detailPageViewModel.hdPrice != -1  | 
            |
| 102 | 
                -// weakself.navigationController?.pushViewController(fullPicCtl, animated: true)  | 
            |
| 103 | 
                -// }  | 
            |
| 104 | 
                -// })  | 
            |
| 105 | 
                -// }.disposed(by: disposeBag)  | 
            |
| 106 | 
                - }  | 
            |
| 107 | 
                -        do {
               | 
            |
| 108 | 
                -// NotificationCenter.default.rx.notification(Notification.Name.UIKeyboardWillShow)  | 
            |
| 109 | 
                -// .asObservable()  | 
            |
| 110 | 
                -//                .subscribe({ (notification) in
               | 
            |
| 111 | 
                -//                    guard let info = notification.element?.userInfo, let avalue = info[UIKeyboardFrameEndUserInfoKey] else {
               | 
            |
| 112 | 
                -// return  | 
            |
| 113 | 
                -// }  | 
            |
| 114 | 
                -//  | 
            |
| 115 | 
                -// let height = (avalue as AnyObject).cgRectValue.size.height  | 
            |
| 116 | 
                -// self.returnKeyboarAction(notification.element!, height: height)  | 
            |
| 117 | 
                -// }).disposed(by: disposeBag)  | 
            |
| 118 | 
                - }  | 
            |
| 119 | 
                -  | 
            |
| 120 | 
                -        do {
               | 
            |
| 121 | 
                - NotificationCenter.default.rx.notification(UIResponder.keyboardWillHideNotification)  | 
            |
| 122 | 
                - .asObservable()  | 
            |
| 123 | 
                -                .subscribe({ (notification) in
               | 
            |
| 124 | 
                - self.returnKeyboarAction(notification.element!, height: 0)  | 
            |
| 125 | 
                - }).disposed(by: disposeBag)  | 
            |
| 126 | 
                - }  | 
            |
| 127 | 
                -  | 
            |
| 79 | 
                + viewModel.viewWillAppear.accept(())  | 
            |
| 128 | 80 | 
                }  | 
            
| 81 | 
                +}  | 
            |
| 129 | 82 | 
                 | 
            
| 130 | 
                - // MARK: refresh interface  | 
            |
| 131 | 
                -    func refreshUI(index: Int) {
               | 
            |
| 132 | 
                - currentPhotoIndex = index  | 
            |
| 133 | 
                -// detailPageViewModel.currentPhoto = datas[index]  | 
            |
| 134 | 
                -  | 
            |
| 135 | 
                -//        detailPageViewModel.fetchThumbup(success: {[weak self] in
               | 
            |
| 136 | 
                -//            if let weakself = self {
               | 
            |
| 137 | 
                -// var model = weakself.datas[index]  | 
            |
| 138 | 
                -// model.thumbup_num = weakself.detailPageViewModel.thumbups.count  | 
            |
| 139 | 
                -// weakself.datas[index] = model  | 
            |
| 140 | 
                -//// PhotoLocalStorage.instance.updateLocalData(PhotoItem: model)  | 
            |
| 141 | 
                -// weakself.reloadSection(inter: 3)  | 
            |
| 142 | 
                -// }  | 
            |
| 143 | 
                -// })  | 
            |
| 144 | 
                -//        detailPageViewModel.fetchComment(success: {[weak self] in
               | 
            |
| 145 | 
                -//            if let weakself = self {
               | 
            |
| 146 | 
                -//  | 
            |
| 147 | 
                -// var model = weakself.datas[index]  | 
            |
| 148 | 
                -// model.comment_num = weakself.detailPageViewModel.comments.count  | 
            |
| 149 | 
                -// weakself.datas[index] = model  | 
            |
| 150 | 
                -//// PhotoLocalStorage.instance.updateLocalData(PhotoItem: model)  | 
            |
| 151 | 
                -// weakself.reloadSection(inter: 4)  | 
            |
| 152 | 
                -// }  | 
            |
| 153 | 
                -// })  | 
            |
| 83 | 
                +//MARK textField delegate  | 
            |
| 84 | 
                +extension PhotoDetailViewController: UIGestureRecognizerDelegate {
               | 
            |
| 85 | 
                + // MARK: textField  | 
            |
| 154 | 86 | 
                 | 
            
| 155 | 
                -// reloadSection(inter: 0)  | 
            |
| 156 | 
                -// reloadSection(inter: 2)  | 
            |
| 157 | 
                - showBuyView()  | 
            |
| 87 | 
                +    func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
               | 
            |
| 88 | 
                + return commentTextField.isFirstResponder  | 
            |
| 158 | 89 | 
                }  | 
            
| 90 | 
                +  | 
            |
| 91 | 
                +}  | 
            |
| 159 | 92 | 
                 | 
            
| 160 | 
                -    func showBuyView() {
               | 
            |
| 161 | 
                -//        if detailPageViewModel.currentPhoto.photo_from == kPhotographerMark && detailPageViewModel.currentPhoto.display_payment_btn == 1 {
               | 
            |
| 162 | 
                -// buyView.isHidden = false  | 
            |
| 163 | 
                -// detailPageViewModel.hdPrice = -0.01  | 
            |
| 164 | 
                -// detailPageViewModel.watermarkPrice = -0.01  | 
            |
| 165 | 
                -// shuiyinLabel.text = !detailPageViewModel.currentPhoto.murl.isEmpty ? "查看无水印图" : "去除水印"  | 
            |
| 166 | 
                -// shuiyinImage.isHidden = false  | 
            |
| 167 | 
                -//        } else {
               | 
            |
| 168 | 
                -// buyView.isHidden = true  | 
            |
| 169 | 
                -// }  | 
            |
| 170 | 
                - }  | 
            |
| 171 | 93 | 
                 | 
            
| 172 | 
                - // MARK: Storyboard button function  | 
            |
| 173 | 
                -    @IBAction func HDPay(_ sender: UIButton) {
               | 
            |
| 174 | 
                -//        detailPageViewModel.getHD (getPriceSuccess: { [weak self] (isExist) in
               | 
            |
| 175 | 
                -//            if let weakself = self {
               | 
            |
| 176 | 
                -//                if isExist {
               | 
            |
| 177 | 
                -// let fullPicCtl = UIStoryboard(name: "Detail", bundle: nil).instantiateController(ShowFullPicController.self)  | 
            |
| 178 | 
                -// fullPicCtl.datas = [weakself.datas[weakself.currentPhotoIndex]]  | 
            |
| 179 | 
                -// fullPicCtl.showNomark = true  | 
            |
| 180 | 
                -// fullPicCtl.currentPhotoIndex = weakself.currentPhotoIndex  | 
            |
| 181 | 
                -// weakself.navigationController?.pushViewController(fullPicCtl, animated: true)  | 
            |
| 182 | 
                -//                } else {
               | 
            |
| 183 | 
                -// }  | 
            |
| 184 | 
                -// }  | 
            |
| 185 | 
                -// })  | 
            |
| 94 | 
                +/// bind storyboard gesture action  | 
            |
| 95 | 
                +extension PhotoDetailViewController {
               | 
            |
| 96 | 
                +    @IBAction func purchase(_ sender: UITapGestureRecognizer) {
               | 
            |
| 97 | 
                +  | 
            |
| 186 | 98 | 
                }  | 
            
| 187 | 
                -  | 
            |
| 188 | 
                -    @IBAction func waterMarkPay(_ sender: UIButton) {
               | 
            |
| 189 | 
                -  | 
            |
| 190 | 
                -//        detailPageViewModel.getWatermark (getPriceSuccess: { [weak self] (isExist) in
               | 
            |
| 191 | 
                -//            if let weakself = self {
               | 
            |
| 192 | 
                -//                if isExist {
               | 
            |
| 193 | 
                -// let fullPicCtl = UIStoryboard(name: "Detail", bundle: nil).instantiateController(ShowFullPicController.self)  | 
            |
| 194 | 
                -// fullPicCtl.datas = weakself.datas  | 
            |
| 195 | 
                -// fullPicCtl.showNomark = true  | 
            |
| 196 | 
                -// fullPicCtl.currentPhotoIndex = weakself.currentPhotoIndex  | 
            |
| 197 | 
                -// weakself.navigationController?.pushViewController(fullPicCtl, animated: true)  | 
            |
| 198 | 
                -//                } else {
               | 
            |
| 199 | 
                -// weakself.shuiyinImage.isHidden = true  | 
            |
| 200 | 
                -// weakself.shuiyinLabel.text = "¥\((weakself.detailPageViewModel.watermarkPrice/100))"  | 
            |
| 201 | 
                -// }  | 
            |
| 202 | 
                -// }  | 
            |
| 203 | 
                -// })  | 
            |
| 99 | 
                +  | 
            |
| 100 | 
                +    @IBAction func enterGroup(_ sender: UITapGestureRecognizer) {
               | 
            |
| 101 | 
                + self.viewModel.navigateToGroup()  | 
            |
| 204 | 102 | 
                }  | 
            
| 103 | 
                +}  | 
            |
| 205 | 104 | 
                 | 
            
| 105 | 
                +/// bind storyboard button action  | 
            |
| 106 | 
                +extension PhotoDetailViewController {
               | 
            |
| 206 | 107 | 
                     @IBAction func share() {
               | 
            
| 207 | 108 | 
                let ctl = UIStoryboard.photoDetail.instantiateController(ShareController.self)  | 
            
| 208 | 109 | 
                ctl.shareContent = "我使用拍爱分享了一张美图,你也快来试试吧"  | 
            
| 209 | 
                - ctl.shareImgUrlThumb = datas[currentPhotoIndex].photo_thumbnail_url  | 
            |
| 210 | 
                - ctl.shareUrl = datas[currentPhotoIndex].photo_share_url  | 
            |
| 110 | 
                + // ctl.shareImgUrlThumb = datas[currentPhotoIndex].photo_thumbnail_url  | 
            |
| 111 | 
                + // ctl.shareUrl = datas[currentPhotoIndex].photo_share_url  | 
            |
| 211 | 112 | 
                presentController(ctl)  | 
            
| 212 | 113 | 
                }  | 
            
| 213 | 
                -  | 
            |
| 114 | 
                +  | 
            |
| 214 | 115 | 
                     @IBAction func comment() {
               | 
            
| 215 | 
                - commentView.isHidden = false  | 
            |
| 216 | 116 | 
                commentTextField.becomeFirstResponder()  | 
            
| 117 | 
                +  | 
            |
| 217 | 118 | 
                }  | 
            
| 218 | 
                -  | 
            |
| 119 | 
                +  | 
            |
| 219 | 120 | 
                     @IBAction func sendComment() {
               | 
            
| 220 | 
                -        guard let text = commentTextField.text else {
               | 
            |
| 221 | 
                - return  | 
            |
| 222 | 
                - }  | 
            |
| 223 | 
                -//        detailPageViewModel.sendComment(content: text, success: { [weak self] in
               | 
            |
| 224 | 
                -//            if let weakself = self {
               | 
            |
| 225 | 
                -// weakself.commentTextField.text = ""  | 
            |
| 226 | 
                -// weakself.commentTextField.resignFirstResponder()  | 
            |
| 227 | 
                -// weakself.commentView.isHidden = true  | 
            |
| 228 | 
                -// weakself.refreshUI(index: weakself.currentPhotoIndex)  | 
            |
| 229 | 
                -// }  | 
            |
| 230 | 
                -// })  | 
            |
| 121 | 
                +        guard let text = commentTextField.text else { return }
               | 
            |
| 122 | 
                +  | 
            |
| 123 | 
                + viewModel.submitComment(text: text)  | 
            |
| 124 | 
                + commentTextField.resignFirstResponder()  | 
            |
| 231 | 125 | 
                }  | 
            
| 232 | 
                -  | 
            |
| 126 | 
                +  | 
            |
| 233 | 127 | 
                     @IBAction func thumbup() {
               | 
            
| 234 | 
                -//        detailPageViewModel.sendThumbup(success: {[weak self]  in
               | 
            |
| 235 | 
                -//            if let weakself = self {
               | 
            |
| 236 | 
                -// weakself.refreshUI(index: weakself.currentPhotoIndex)  | 
            |
| 237 | 
                -// }  | 
            |
| 238 | 
                -//  | 
            |
| 239 | 
                -// })  | 
            |
| 128 | 
                + viewModel.submitThumbup()  | 
            |
| 240 | 129 | 
                }  | 
            
| 130 | 
                +}  | 
            |
| 241 | 131 | 
                 | 
            
| 242 | 
                - // MARK: custom function  | 
            |
| 243 | 
                -    func reloadSection(inter: Int) {
               | 
            |
| 244 | 
                - tableView.beginUpdates()  | 
            |
| 245 | 
                - let indexSet = IndexSet(integer: inter)  | 
            |
| 246 | 
                - tableView.reloadSections(indexSet, with: .none)  | 
            |
| 247 | 
                - tableView.endUpdates()  | 
            |
| 132 | 
                +/// bind rx  | 
            |
| 133 | 
                +extension PhotoDetailViewController {
               | 
            |
| 134 | 
                +  | 
            |
| 135 | 
                +    var commentTableViewDataSource: RxTableViewSectionedAnimatedDataSource<AnimatableSectionModel<Int, PhotoCommentItem>> {
               | 
            |
| 136 | 
                +        return RxTableViewSectionedAnimatedDataSource<AnimatableSectionModel<Int, PhotoCommentItem>>(configureCell: { (dataSource, tableView, indexPath, item) in
               | 
            |
| 137 | 
                + let cell = tableView.dequeueReusableCell(withIdentifier: "photoDetailCommentCell", for: indexPath) as! PhotoDetailCommentCell  | 
            |
| 138 | 
                + cell.setInfo(item)  | 
            |
| 139 | 
                + return cell  | 
            |
| 140 | 
                + })  | 
            |
| 248 | 141 | 
                }  | 
            
| 249 | 
                -  | 
            |
| 250 | 
                -    @objc func showThumps() {
               | 
            |
| 251 | 
                -//        if detailPageViewModel.thumbupsCount > 0 {
               | 
            |
| 252 | 
                -// detailPageViewModel.thumbupsCount = 0  | 
            |
| 253 | 
                -//        } else {
               | 
            |
| 254 | 
                -// detailPageViewModel.thumbupsCount = detailPageViewModel.thumbups.count  | 
            |
| 255 | 
                -// }  | 
            |
| 256 | 
                - reloadSection(inter: 3)  | 
            |
| 257 | 
                - }  | 
            |
| 258 | 
                -    @objc func showComments() {
               | 
            |
| 259 | 
                -//        if detailPageViewModel.commentsCount > 0 {
               | 
            |
| 260 | 
                -// detailPageViewModel.commentsCount = 0  | 
            |
| 261 | 
                -//        } else {
               | 
            |
| 262 | 
                -// detailPageViewModel.commentsCount = detailPageViewModel.comments.count  | 
            |
| 263 | 
                -// }  | 
            |
| 264 | 
                - reloadSection(inter: 4)  | 
            |
| 142 | 
                +  | 
            |
| 143 | 
                +    var photoCollectionViewDataSource: RxCollectionViewSectionedAnimatedDataSource<AnimatableSectionModel<Int, PhotoItem>> {
               | 
            |
| 144 | 
                +        return RxCollectionViewSectionedAnimatedDataSource<AnimatableSectionModel<Int, PhotoItem>>(configureCell: { (dataSource, collectionView, indexPath, item) in
               | 
            |
| 145 | 
                + let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "photoDetailImageCell", for: indexPath) as! PhotoDetailImageCell  | 
            |
| 146 | 
                + cell.imageView.setImage(item.photo_thumbnail2_url, placeholder: UIImage.photoPlaceholder)  | 
            |
| 147 | 
                + return cell  | 
            |
| 148 | 
                + })  | 
            |
| 265 | 149 | 
                }  | 
            
| 266 | 
                -  | 
            |
| 267 | 
                -    @objc func loadReportController() {
               | 
            |
| 268 | 
                -// let ctl = UIStoryboard.photoDetail.instantiateController(ReportController.self)  | 
            |
| 269 | 
                -// presentController(ctl)  | 
            |
| 150 | 
                +  | 
            |
| 151 | 
                +    func binding() {
               | 
            |
| 152 | 
                + bindEnterGroupViewHiddenState()  | 
            |
| 153 | 
                + bindViewModelToGroupName()  | 
            |
| 154 | 
                + bindViewModelToGroupAvatar()  | 
            |
| 155 | 
                +  | 
            |
| 156 | 
                + bindViewModelToUserName()  | 
            |
| 157 | 
                + bindgingViewModelToUserAvatar()  | 
            |
| 158 | 
                +  | 
            |
| 159 | 
                + bindViewModelToThumbupCount()  | 
            |
| 160 | 
                + bindViewModelToThumbupView()  | 
            |
| 161 | 
                +  | 
            |
| 162 | 
                + bindViewModelToCommentCount()  | 
            |
| 163 | 
                + bindViewModelToCommentTableView()  | 
            |
| 164 | 
                +  | 
            |
| 165 | 
                + bindBuyViewIsVisiable()  | 
            |
| 166 | 
                +  | 
            |
| 167 | 
                + bindCommentTextFieldToSendBtn()  | 
            |
| 168 | 
                +  | 
            |
| 169 | 
                + bindCollectionViewDelegate()  | 
            |
| 170 | 
                + bindCollectionViewSelected()  | 
            |
| 171 | 
                + bindCollectionViewToListViewModel()  | 
            |
| 172 | 
                + bindListViewModelToCollectionView()  | 
            |
| 173 | 
                +  | 
            |
| 174 | 
                + bindViewWillAppear()  | 
            |
| 175 | 
                +  | 
            |
| 176 | 
                + monitorKeyboardWillShow()  | 
            |
| 177 | 
                + monitorKeyboardWillHide()  | 
            |
| 270 | 178 | 
                }  | 
            
| 271 | 
                -  | 
            |
| 272 | 
                -    func returnKeyboarAction(_ notification: Notification, height: CGFloat) {
               | 
            |
| 273 | 
                -        guard let info = (notification as NSNotification).userInfo, let duration = info[UIResponder.keyboardAnimationDurationUserInfoKey] as? TimeInterval else {
               | 
            |
| 274 | 
                - return  | 
            |
| 275 | 
                - }  | 
            |
| 276 | 
                -  | 
            |
| 277 | 
                -        UIView.animate(withDuration: duration, animations: {() -> Void in
               | 
            |
| 278 | 
                - self.commentHeight.constant = height  | 
            |
| 279 | 
                - self.commentView.superview!.layoutIfNeeded()  | 
            |
| 280 | 
                - })  | 
            |
| 179 | 
                +  | 
            |
| 180 | 
                +    func bindEnterGroupViewHiddenState() {
               | 
            |
| 181 | 
                + viewModel.isHiddenEnterGroupBtn.bind(to: enterGroupView.rx.isHidden).disposed(by: disposeBag)  | 
            |
| 281 | 182 | 
                }  | 
            
| 282 | 
                -  | 
            |
| 283 | 
                - // MARK: deinit  | 
            |
| 284 | 
                -    deinit {
               | 
            |
| 285 | 
                - NotificationCenter.default.removeObserver(self)  | 
            |
| 183 | 
                +  | 
            |
| 184 | 
                +    func bindViewModelToGroupName() {
               | 
            |
| 185 | 
                + viewModel.groupName.bind(to: groupName.rx.text).disposed(by: disposeBag)  | 
            |
| 286 | 186 | 
                }  | 
            
| 287 | 
                -  | 
            |
| 288 | 
                -}  | 
            |
| 289 | 
                -  | 
            |
| 290 | 
                -// MARK: custom delegate function  | 
            |
| 291 | 
                -extension PhotoDetailViewController: CellDelegate {
               | 
            |
| 292 | 
                -    func selectIndex(indexpath: IndexPath) {
               | 
            |
| 293 | 
                - let ctl = UIStoryboard.photoDetail.instantiateController(ShowFullPicController.self)  | 
            |
| 294 | 
                - ctl.datas = datas  | 
            |
| 295 | 
                - ctl.currentPhotoIndex = currentPhotoIndex  | 
            |
| 296 | 
                - show(ctl, sender: nil)  | 
            |
| 187 | 
                +  | 
            |
| 188 | 
                +    func bindViewModelToGroupAvatar() {
               | 
            |
| 189 | 
                + viewModel.groupAvatar  | 
            |
| 190 | 
                +            .subscribe(onNext: {[weak self] (avatar) in
               | 
            |
| 191 | 
                +            guard let `self` = self else { return }
               | 
            |
| 192 | 
                + self.groupAvatar.setImage(avatar)  | 
            |
| 193 | 
                + }).disposed(by: disposeBag)  | 
            |
| 297 | 194 | 
                }  | 
            
| 298 | 
                -  | 
            |
| 299 | 
                -    func returnCurrentIndex(index: Int) {
               | 
            |
| 300 | 
                - refreshUI(index: index)  | 
            |
| 195 | 
                +  | 
            |
| 196 | 
                +    func bindgingViewModelToUserAvatar() {
               | 
            |
| 197 | 
                + viewModel.userAvatar  | 
            |
| 198 | 
                +            .subscribe(onNext: {[weak self] (avatar) in
               | 
            |
| 199 | 
                +                guard let `self` = self else { return }
               | 
            |
| 200 | 
                + self.userAvatar.setImage(avatar)  | 
            |
| 201 | 
                + }).disposed(by: disposeBag)  | 
            |
| 301 | 202 | 
                }  | 
            
| 302 | 
                -  | 
            |
| 303 | 
                -    func pushNext() {
               | 
            |
| 304 | 
                - let ctl = UIStoryboard.main.instantiateController(GroupViewController.self)  | 
            |
| 305 | 
                -  | 
            |
| 306 | 
                -// ctl.groupModel = GroupModel(map: Map(mappingType: .fromJSON, JSON: datas[currentPhotoIndex].toJSON()))  | 
            |
| 307 | 
                - show(ctl, sender: nil)  | 
            |
| 203 | 
                +  | 
            |
| 204 | 
                +    func bindViewModelToUserName() {
               | 
            |
| 205 | 
                + viewModel.groupName.bind(to: userName.rx.text).disposed(by: disposeBag)  | 
            |
| 308 | 206 | 
                }  | 
            
| 309 | 
                -}  | 
            |
| 310 | 
                -  | 
            |
| 311 | 
                -//MARK textField delegate  | 
            |
| 312 | 
                -extension PhotoDetailViewController: UIGestureRecognizerDelegate {
               | 
            |
| 313 | 
                - // MARK: textField  | 
            |
| 314 | 
                -  | 
            |
| 315 | 
                -    func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
               | 
            |
| 316 | 
                - return commentTextField.isFirstResponder  | 
            |
| 207 | 
                +  | 
            |
| 208 | 
                +    func bindViewModelToPhotoTime() {
               | 
            |
| 209 | 
                + viewModel.photoTime.bind(to: photoTime.rx.text).disposed(by: disposeBag)  | 
            |
| 317 | 210 | 
                }  | 
            
| 318 | 
                -  | 
            |
| 319 | 
                -    @IBAction func ReturnKeyboard(_ sender: UITapGestureRecognizer) {
               | 
            |
| 320 | 
                -        if !commentView.isHidden {
               | 
            |
| 321 | 
                - commentTextField.resignFirstResponder()  | 
            |
| 322 | 
                - commentView.isHidden = true  | 
            |
| 323 | 
                - }  | 
            |
| 211 | 
                +  | 
            |
| 212 | 
                +    func bindViewModelToThumbupCount() {
               | 
            |
| 213 | 
                + viewModel.thumbupCount.bind(to: thumbupCount.rx.text).disposed(by: disposeBag)  | 
            |
| 324 | 214 | 
                }  | 
            
| 325 | 
                -  | 
            |
| 326 | 
                -}  | 
            |
| 327 | 
                -  | 
            |
| 328 | 
                -// MARK: UITableView delegate  | 
            |
| 329 | 
                -extension PhotoDetailViewController: UITableViewDataSource, UITableViewDelegate {
               | 
            |
| 330 | 
                -  | 
            |
| 331 | 
                -    func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
               | 
            |
| 332 | 
                -        if section == 3 {
               | 
            |
| 333 | 
                - let cell = tableView.dequeueReusableCell(withIdentifier: "thumbupHeadCell")  | 
            |
| 334 | 
                -            if let label = cell?.viewWithTag(1001) as? UILabel {
               | 
            |
| 335 | 
                -// label.text = "(\(detailPageViewModel.thumbups.count))"  | 
            |
| 336 | 
                - }  | 
            |
| 337 | 
                -            if let button = cell?.viewWithTag(1011) as? UIButton {
               | 
            |
| 338 | 
                - button.addTarget(self, action: #selector(showThumps), for: .touchUpInside)  | 
            |
| 339 | 
                - }  | 
            |
| 340 | 
                -            if let imageView = cell?.viewWithTag(1008) as? UIImageView {
               | 
            |
| 341 | 
                -// let imageName = detailPageViewModel.thumbupsCount <= 0 ? "收起" : "list-arrow"  | 
            |
| 342 | 
                -// imageView.image = UIImage(named : imageName)  | 
            |
| 343 | 
                - }  | 
            |
| 344 | 
                - return cell?.contentView  | 
            |
| 345 | 
                -        } else if section == 4 {
               | 
            |
| 346 | 
                - let cell = tableView.dequeueReusableCell(withIdentifier: "comentHeadCell")  | 
            |
| 347 | 
                -            if let label = cell?.viewWithTag(1002) as? UILabel {
               | 
            |
| 348 | 
                -// label.text = "(\(detailPageViewModel.comments.count))"  | 
            |
| 349 | 
                - }  | 
            |
| 350 | 
                -            if let button = cell?.viewWithTag(1012) as? UIButton {
               | 
            |
| 351 | 
                - button.addTarget(self, action: #selector(showComments), for: .touchUpInside)  | 
            |
| 352 | 
                - }  | 
            |
| 353 | 
                -            if let imageView = cell?.viewWithTag(1009) as? UIImageView {
               | 
            |
| 354 | 
                -// let imageName = detailPageViewModel.commentsCount <= 0 ? "收起" : "list-arrow"  | 
            |
| 355 | 
                -// imageView.image = UIImage(named : imageName)  | 
            |
| 356 | 
                - }  | 
            |
| 357 | 
                - return cell?.contentView  | 
            |
| 358 | 
                - }  | 
            |
| 359 | 
                - return nil  | 
            |
| 215 | 
                +  | 
            |
| 216 | 
                +    func bindViewModelToThumbupView() {
               | 
            |
| 217 | 
                + viewModel.thumbupItems  | 
            |
| 218 | 
                + .asDriver(onErrorJustReturn: [])  | 
            |
| 219 | 
                +            .drive(onNext: { [weak self] (items) in
               | 
            |
| 220 | 
                + self?.setupThumbupView(items: items)  | 
            |
| 221 | 
                + }).disposed(by: disposeBag)  | 
            |
| 360 | 222 | 
                }  | 
            
| 361 | 
                -  | 
            |
| 362 | 
                -    func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
               | 
            |
| 363 | 
                -        if section == 3 || section == 4 {
               | 
            |
| 364 | 
                - return 44  | 
            |
| 365 | 
                - }  | 
            |
| 366 | 
                - return 0  | 
            |
| 223 | 
                +  | 
            |
| 224 | 
                +    func bindViewModelToCommentCount() {
               | 
            |
| 225 | 
                + viewModel.commentCount.bind(to: commentCount.rx.text).disposed(by: disposeBag)  | 
            |
| 367 | 226 | 
                }  | 
            
| 368 | 
                -  | 
            |
| 369 | 
                -    func numberOfSections(in tableView: UITableView) -> Int {
               | 
            |
| 370 | 
                - return 0  | 
            |
| 227 | 
                +  | 
            |
| 228 | 
                +    func bindViewModelToCommentTableView() {
               | 
            |
| 229 | 
                + viewModel.commentItems  | 
            |
| 230 | 
                + .bind(to: commentTableView.rx.items(dataSource: commentTableViewDataSource))  | 
            |
| 231 | 
                + .disposed(by: disposeBag)  | 
            |
| 371 | 232 | 
                }  | 
            
| 372 | 
                -  | 
            |
| 373 | 
                -    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
               | 
            |
| 374 | 
                -//        if section == 3 {
               | 
            |
| 375 | 
                -// return detailPageViewModel.thumbupsCount > 0 ? 1 : 0  | 
            |
| 376 | 
                -//        } else if section == 4 {
               | 
            |
| 377 | 
                -// return detailPageViewModel.commentsCount  | 
            |
| 378 | 
                -// }  | 
            |
| 379 | 
                - return 0  | 
            |
| 233 | 
                +  | 
            |
| 234 | 
                +    func bindBuyViewIsVisiable() {
               | 
            |
| 235 | 
                +        viewModel.canBuy.map { !$0 }.bind(to: buyView.rx.isHidden).disposed(by: disposeBag)
               | 
            |
| 380 | 236 | 
                }  | 
            
| 381 | 
                -  | 
            |
| 382 | 
                -    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
               | 
            |
| 383 | 
                -        if indexPath.section == 0 {
               | 
            |
| 384 | 
                - let cell = tableView.dequeueReusableCell(withIdentifier: "headCell", for: indexPath) as! DetailPageHeadCell  | 
            |
| 385 | 
                - cell.enterView.isHidden = isHiddenEnterView  | 
            |
| 386 | 
                -// cell.setInfo(datas[currentPhotoIndex])  | 
            |
| 387 | 
                - cell.delegate = self  | 
            |
| 388 | 
                -            if let reportBtn = cell.viewWithTag(40001) as? UIButton {
               | 
            |
| 389 | 
                -  | 
            |
| 390 | 
                - reportBtn.addTarget(self, action: #selector(loadReportController), for: .touchUpInside)  | 
            |
| 391 | 
                -// reportBtn.isHidden = !(UserDefaults.Account.bool(forKey: .isAudit))  | 
            |
| 392 | 
                - }  | 
            |
| 393 | 
                - return cell  | 
            |
| 394 | 
                -        } else if indexPath.section == 1 {
               | 
            |
| 395 | 
                - let cell = tableView.dequeueReusableCell(withIdentifier: "detailPagePhotoCell", for: indexPath) as! DetailPagePhotoCell  | 
            |
| 396 | 
                -// cell.datas = datas  | 
            |
| 397 | 
                -// cell.currentPhotoIndex = currentPhotoIndex  | 
            |
| 398 | 
                - cell.delegate = self  | 
            |
| 399 | 
                - cell.first = true  | 
            |
| 400 | 
                - cell.collectionView.reloadData()  | 
            |
| 401 | 
                - return cell  | 
            |
| 402 | 
                -        } else if indexPath.section == 2 {
               | 
            |
| 403 | 
                - let cell = tableView.dequeueReusableCell(withIdentifier: "nameCell", for: indexPath) as! DetailPageNameCell  | 
            |
| 404 | 
                -// cell.setInfo(datas[currentPhotoIndex])  | 
            |
| 405 | 
                - return cell  | 
            |
| 406 | 
                -        } else if indexPath.section == 3 {
               | 
            |
| 407 | 
                - let cell = tableView.dequeueReusableCell(withIdentifier: "thumbupCell", for: indexPath) as! DetailthumbupImagesCell  | 
            |
| 408 | 
                -//            if detailPageViewModel.thumbups.count > 0 {
               | 
            |
| 409 | 
                -//                let headers = detailPageViewModel.thumbups.map {$0.avatar}
               | 
            |
| 410 | 
                -// cell.setInfo(content: headers)  | 
            |
| 411 | 
                -// }  | 
            |
| 412 | 
                - return cell  | 
            |
| 413 | 
                -        } else {
               | 
            |
| 414 | 
                - let cell = tableView.dequeueReusableCell(withIdentifier: "comentCell", for: indexPath) as! DetailCommentCell  | 
            |
| 415 | 
                -// cell.setInfo(detailPageViewModel.comments[indexPath.row])  | 
            |
| 416 | 
                - return cell  | 
            |
| 417 | 
                - }  | 
            |
| 237 | 
                +  | 
            |
| 238 | 
                +    func bindCommentTextFieldToSendBtn() {
               | 
            |
| 239 | 
                + commentTextField.rx.text  | 
            |
| 240 | 
                +            .map { !($0?.isEmpty)! }
               | 
            |
| 241 | 
                + .bind(to: sendBtn.rx.isEnabled)  | 
            |
| 242 | 
                + .disposed(by: disposeBag)  | 
            |
| 243 | 
                + }  | 
            |
| 244 | 
                +  | 
            |
| 245 | 
                +    func bindCollectionViewDelegate() {
               | 
            |
| 246 | 
                + photoCollectionView.rx.setDelegate(self).disposed(by: disposeBag)  | 
            |
| 247 | 
                +  | 
            |
| 248 | 
                + }  | 
            |
| 249 | 
                +  | 
            |
| 250 | 
                +    func bindListViewModelToCollectionView() {
               | 
            |
| 251 | 
                + listViewModel.content  | 
            |
| 252 | 
                + .bind(to: photoCollectionView.rx.items(dataSource: photoCollectionViewDataSource))  | 
            |
| 253 | 
                + .disposed(by: disposeBag)  | 
            |
| 254 | 
                + }  | 
            |
| 255 | 
                +  | 
            |
| 256 | 
                +    func bindCollectionViewToListViewModel() {
               | 
            |
| 257 | 
                + photoCollectionView.rx.willDisplayCell  | 
            |
| 258 | 
                + .asDriver()  | 
            |
| 259 | 
                +            .drive(onNext: { [unowned self] in
               | 
            |
| 260 | 
                + self.listViewModel.willShow(index: $0.at.row)  | 
            |
| 261 | 
                + })  | 
            |
| 262 | 
                + .disposed(by: disposeBag)  | 
            |
| 263 | 
                + }  | 
            |
| 264 | 
                +  | 
            |
| 265 | 
                +    func bindCollectionViewSelected() {
               | 
            |
| 266 | 
                + photoCollectionView.rx.itemSelected  | 
            |
| 267 | 
                + .asDriver(onErrorJustReturn: IndexPath(item: 0, section: 0))  | 
            |
| 268 | 
                +            .drive(onNext: { [unowned self] _ in self.listViewModel.didSelected() })
               | 
            |
| 269 | 
                + .disposed(by: disposeBag)  | 
            |
| 270 | 
                + }  | 
            |
| 271 | 
                +  | 
            |
| 272 | 
                +    func bindViewWillAppear() {
               | 
            |
| 273 | 
                + viewModel.viewWillAppear  | 
            |
| 274 | 
                + .asDriver()  | 
            |
| 275 | 
                +            .drive(onNext: { [unowned self] _ in
               | 
            |
| 276 | 
                + self.photoCollectionView.scrollToItem(at: IndexPath(item: self.listViewModel.currIndex, section: 0), at: .right, animated: false)  | 
            |
| 277 | 
                + })  | 
            |
| 278 | 
                + .disposed(by: disposeBag)  | 
            |
| 418 | 279 | 
                }  | 
            
| 280 | 
                +  | 
            |
| 281 | 
                +    func monitorKeyboardWillShow() {
               | 
            |
| 282 | 
                + NotificationCenter.default.rx  | 
            |
| 283 | 
                + .notification(UIResponder.keyboardWillShowNotification)  | 
            |
| 284 | 
                + .takeUntil(self.rx.deallocated)  | 
            |
| 285 | 
                +            .subscribe { [unowned self] notification in
               | 
            |
| 286 | 
                + guard let userInfo = notification.element?.userInfo,  | 
            |
| 287 | 
                + let keyboardFrame = userInfo[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect,  | 
            |
| 288 | 
                + let timeInterval = userInfo[UIResponder.keyboardAnimationDurationUserInfoKey] as? TimeInterval,  | 
            |
| 289 | 
                + let curve = userInfo[UIResponder.keyboardAnimationCurveUserInfoKey] as? Int  | 
            |
| 290 | 
                +                    else { return }
               | 
            |
| 291 | 
                + UIView.setAnimationCurve(UIView.AnimationCurve(rawValue: curve) ?? .linear)  | 
            |
| 292 | 
                +                UIView.animate(withDuration: timeInterval, animations: {
               | 
            |
| 293 | 
                + self.commentEditYConstraint.constant = keyboardFrame.height  | 
            |
| 294 | 
                + self.view.layoutIfNeeded()  | 
            |
| 295 | 
                + })  | 
            |
| 296 | 
                + }.disposed(by: disposeBag)  | 
            |
| 297 | 
                + }  | 
            |
| 298 | 
                +  | 
            |
| 299 | 
                +    func monitorKeyboardWillHide() {
               | 
            |
| 300 | 
                + NotificationCenter.default.rx  | 
            |
| 301 | 
                + .notification(UIResponder.keyboardWillHideNotification)  | 
            |
| 302 | 
                + .takeUntil(self.rx.deallocated)  | 
            |
| 303 | 
                +            .subscribe { [unowned self] notification in
               | 
            |
| 304 | 
                + guard let userInfo = notification.element?.userInfo,  | 
            |
| 305 | 
                + let timeInterval = userInfo[UIResponder.keyboardAnimationDurationUserInfoKey] as? TimeInterval,  | 
            |
| 306 | 
                + let curve = userInfo[UIResponder.keyboardAnimationCurveUserInfoKey] as? Int  | 
            |
| 307 | 
                +                    else { return }
               | 
            |
| 308 | 
                + UIView.setAnimationCurve(UIView.AnimationCurve(rawValue: curve) ?? .linear)  | 
            |
| 309 | 
                +                UIView.animate(withDuration: timeInterval, animations: {
               | 
            |
| 310 | 
                + self.commentEditYConstraint.constant = -56  | 
            |
| 311 | 
                + self.view.layoutIfNeeded()  | 
            |
| 312 | 
                + })  | 
            |
| 313 | 
                + self.commentTextField.clear()  | 
            |
| 314 | 
                + }.disposed(by: disposeBag)  | 
            |
| 315 | 
                + }  | 
            |
| 316 | 
                +}  | 
            |
| 419 | 317 | 
                 | 
            
| 420 | 
                -    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
               | 
            |
| 421 | 
                -        if indexPath.section == 0 {
               | 
            |
| 422 | 
                - return 48  | 
            |
| 423 | 
                -        } else if indexPath.section == 1 {
               | 
            |
| 424 | 
                - return 360  | 
            |
| 425 | 
                -        } else if indexPath.section == 2 {
               | 
            |
| 426 | 
                - return 36  | 
            |
| 427 | 
                -        } else if indexPath.section == 3 {
               | 
            |
| 428 | 
                - return 40  | 
            |
| 429 | 
                -        } else {
               | 
            |
| 430 | 
                -// return 40 + detailPageViewModel.comments[indexPath.row].cellHeigth  | 
            |
| 431 | 
                - return 40  | 
            |
| 318 | 
                +extension PhotoDetailViewController {
               | 
            |
| 319 | 
                +    func setupThumbupView(items: [PhotoThumbupUserItem]) {
               | 
            |
| 320 | 
                +        thumbupView.subviews.forEach { $0.removeFromSuperview() }
               | 
            |
| 321 | 
                +  | 
            |
| 322 | 
                + let row = (Int(kScreenWidth) - 6) / 34  | 
            |
| 323 | 
                + var topConstraint: CGFloat = 6  | 
            |
| 324 | 
                + var last: UIImageView?  | 
            |
| 325 | 
                +  | 
            |
| 326 | 
                +        for (index, item) in items.enumerated() {
               | 
            |
| 327 | 
                + let imageView = UIImageView()  | 
            |
| 328 | 
                + imageView.cornerRadius = 5  | 
            |
| 329 | 
                + imageView.translatesAutoresizingMaskIntoConstraints = false  | 
            |
| 330 | 
                + imageView.setImage(item.avatar, placeholder: UIImage.defaultAvatar)  | 
            |
| 331 | 
                + thumbupView.addSubview(imageView)  | 
            |
| 332 | 
                +  | 
            |
| 333 | 
                +            if index % row == 0 && index != 0 {
               | 
            |
| 334 | 
                + topConstraint += 28 + 6  | 
            |
| 335 | 
                + last = nil  | 
            |
| 336 | 
                + }  | 
            |
| 337 | 
                +  | 
            |
| 338 | 
                + NSLayoutConstraint.activate([  | 
            |
| 339 | 
                + imageView.widthAnchor.constraint(equalToConstant: 28),  | 
            |
| 340 | 
                + imageView.heightAnchor.constraint(equalToConstant: 28),  | 
            |
| 341 | 
                + imageView.topAnchor.constraint(equalTo: thumbupView.topAnchor, constant: topConstraint),  | 
            |
| 342 | 
                + imageView.leadingAnchor.constraint(equalTo: last?.trailingAnchor ?? thumbupView.leadingAnchor, constant: 6)  | 
            |
| 343 | 
                + ])  | 
            |
| 344 | 
                +  | 
            |
| 345 | 
                + last = imageView  | 
            |
| 432 | 346 | 
                }  | 
            
| 347 | 
                + thumbupViewHeightConstraint.constant = items.isEmpty ? 1 : topConstraint + 34  | 
            |
| 348 | 
                + commentTableView.tableHeaderView?.height = 532 + thumbupViewHeightConstraint.constant  | 
            |
| 433 | 349 | 
                }  | 
            
| 434 | 350 | 
                }  | 
            
| 435 | 351 | 
                 | 
            
| 436 | 
                -extension PhotoDetailViewController {
               | 
            |
| 352 | 
                +extension PhotoDetailViewController: UICollectionViewDelegateFlowLayout {
               | 
            |
| 353 | 
                + func collectionView(_ collectionView: UICollectionView,  | 
            |
| 354 | 
                + layout collectionViewLayout: UICollectionViewLayout,  | 
            |
| 355 | 
                +                        sizeForItemAt indexPath: IndexPath) -> CGSize {
               | 
            |
| 356 | 
                + return CGSize(width: kScreenWidth, height: 359)  | 
            |
| 357 | 
                + }  | 
            |
| 437 | 358 | 
                 | 
            
| 359 | 
                +    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
               | 
            |
| 360 | 
                + return 0  | 
            |
| 361 | 
                + }  | 
            |
| 438 | 362 | 
                }  | 
            
| 363 | 
                +  | 
            |
| 364 | 
                +extension PhotoDetailViewController: NavigationBackViewController {}
               | 
            
                @@ -1,5 +1,5 @@  | 
            ||
| 1 | 1 | 
                //  | 
            
| 2 | 
                -// ShowFullPicController.swift  | 
            |
| 2 | 
                +// PhotoPreviewViewController.swift  | 
            |
| 3 | 3 | 
                // PaiAi  | 
            
| 4 | 4 | 
                //  | 
            
| 5 | 5 | 
                // Created by zhengjianfei on 16/4/9.  | 
            
                @@ -9,49 +9,104 @@  | 
            ||
| 9 | 9 | 
                import UIKit  | 
            
| 10 | 10 | 
                import PaiaiDataKit  | 
            
| 11 | 11 | 
                import PaiaiUIKit  | 
            
| 12 | 
                +import RxCocoa  | 
            |
| 13 | 
                +import RxSwift  | 
            |
| 14 | 
                +import RxDataSources  | 
            |
| 12 | 15 | 
                 | 
            
| 13 | 
                -final class ShowFullPicController: UIViewController {
               | 
            |
| 16 | 
                +final class PhotoPreviewViewController: UIViewController {
               | 
            |
| 14 | 17 | 
                 | 
            
| 15 | 
                - // MARK: Storyboard property  | 
            |
| 18 | 
                + /// MARK: Storyboard property  | 
            |
| 16 | 19 | 
                @IBOutlet weak var collectionView: UICollectionView!  | 
            
| 17 | 
                -// @IBOutlet weak var progressView: FFProgress!  | 
            |
| 18 | 
                - // MARK: parameter property  | 
            |
| 19 | 
                - lazy var datas = [PhotoItem]()  | 
            |
| 20 | 
                - lazy var currentPhotoIndex = 0  | 
            |
| 21 | 
                - lazy var firstLayout = true  | 
            |
| 22 | 
                - lazy var currentPageIndex = 0  | 
            |
| 23 | 
                - lazy var showNomark = false  | 
            |
| 24 | 
                - lazy var showHD = false  | 
            |
| 25 | 
                -  | 
            |
| 26 | 
                - var shufflingImage = [String]()  | 
            |
| 27 | 
                -  | 
            |
| 28 | 
                - // MARK: Controller fucntion  | 
            |
| 20 | 
                + var viewModel: PhotoDetailListViewModel!  | 
            |
| 21 | 
                + var disposeBag = DisposeBag()  | 
            |
| 22 | 
                +  | 
            |
| 23 | 
                +    override var prefersStatusBarHidden: Bool {
               | 
            |
| 24 | 
                + return true  | 
            |
| 25 | 
                + }  | 
            |
| 26 | 
                +  | 
            |
| 29 | 27 | 
                     override func viewDidLoad() {
               | 
            
| 30 | 28 | 
                super.viewDidLoad()  | 
            
| 31 | 
                - navigationController?.isNavigationBarHidden = true  | 
            |
| 32 | 
                -// titleWithbackBar = ""  | 
            |
| 33 | 
                -  | 
            |
| 34 | 
                - }  | 
            |
| 35 | 
                -  | 
            |
| 36 | 
                -    override func viewDidLayoutSubviews() {
               | 
            |
| 37 | 
                -        if firstLayout {
               | 
            |
| 38 | 
                - collectionView.contentOffset = CGPoint(x: (CGFloat(currentPhotoIndex) * (collectionView.width)), y: 0)  | 
            |
| 39 | 
                - firstLayout = false  | 
            |
| 29 | 
                + binding()  | 
            |
| 30 | 
                + scrollToSpecifiedImage()  | 
            |
| 31 | 
                + navigationController?.setNavigationBarHidden(true, animated: true)  | 
            |
| 32 | 
                +  | 
            |
| 33 | 
                + }  | 
            |
| 34 | 
                +  | 
            |
| 35 | 
                +    func scrollToSpecifiedImage() {
               | 
            |
| 36 | 
                + collectionView.layoutIfNeeded()  | 
            |
| 37 | 
                + collectionView.scrollToItem(at: IndexPath(item: viewModel.currIndex, section: 0), at: .right, animated: false)  | 
            |
| 38 | 
                + }  | 
            |
| 39 | 
                +  | 
            |
| 40 | 
                +    override func viewDidAppear(_ animated: Bool) {
               | 
            |
| 41 | 
                + super.viewWillAppear(animated)  | 
            |
| 42 | 
                + bindCollectionViewToViewModel()  | 
            |
| 43 | 
                + }  | 
            |
| 44 | 
                +  | 
            |
| 45 | 
                +    override func viewWillDisappear(_ animated: Bool) {
               | 
            |
| 46 | 
                + super.viewWillDisappear(animated)  | 
            |
| 47 | 
                + navigationController?.setNavigationBarHidden(false, animated: true)  | 
            |
| 48 | 
                + }  | 
            |
| 49 | 
                +  | 
            |
| 50 | 
                +    @IBAction func download(_ sender: UIButton) {
               | 
            |
| 51 | 
                + guard let cell = collectionView.cellForItem(at: IndexPath(item: viewModel.currIndex, section: 0)) as? ImageCell,  | 
            |
| 52 | 
                +            let image = cell.photoImage.image else {
               | 
            |
| 53 | 
                + // FFToastView.showToast(inView: view, withText: "未检测到图片")  | 
            |
| 54 | 
                + return  | 
            |
| 40 | 55 | 
                }  | 
            
| 41 | 
                - super.viewDidLayoutSubviews()  | 
            |
| 56 | 
                +  | 
            |
| 57 | 
                + UIImageWriteToSavedPhotosAlbum(image, self, #selector(image(_:didFinishSavingWithError:contextInfo:)), nil)  | 
            |
| 42 | 58 | 
                }  | 
            
| 59 | 
                +  | 
            |
| 60 | 
                +    @objc func image(_ image: UIImage?, didFinishSavingWithError error: NSError?, contextInfo info: UnsafeMutableRawPointer) {
               | 
            |
| 61 | 
                +        if error != nil {
               | 
            |
| 62 | 
                + // FFToastView.showToast(inView: view, withText: "保存图片失败")  | 
            |
| 63 | 
                +        } else {
               | 
            |
| 64 | 
                + // FFToastView.showImageToast(inView: view, withText: "已保存图片到相册", withImage: "提示弹窗-勾")  | 
            |
| 65 | 
                + }  | 
            |
| 66 | 
                + }  | 
            |
| 67 | 
                +}  | 
            |
| 68 | 
                +  | 
            |
| 69 | 
                +/// binding  | 
            |
| 70 | 
                +extension PhotoPreviewViewController {
               | 
            |
| 71 | 
                +  | 
            |
| 72 | 
                +    var dataSource: RxCollectionViewSectionedAnimatedDataSource<AnimatableSectionModel<Int, PhotoItem>> {
               | 
            |
| 73 | 
                +        return RxCollectionViewSectionedAnimatedDataSource<AnimatableSectionModel<Int, PhotoItem>>(configureCell: { (dataSource, collectionView, indexPath, item) in
               | 
            |
| 74 | 
                + let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "imageCell", for: indexPath) as! ImageCell  | 
            |
| 75 | 
                + cell.setModel(url: item.murl.isEmpty ? item.photo_url : item.murl)  | 
            |
| 76 | 
                + return cell  | 
            |
| 77 | 
                + })  | 
            |
| 78 | 
                + }  | 
            |
| 79 | 
                +  | 
            |
| 80 | 
                +    func binding() {
               | 
            |
| 81 | 
                + bindViewModelToCollectionView()  | 
            |
| 82 | 
                + bindCollectionViewDelegate()  | 
            |
| 83 | 
                + }  | 
            |
| 84 | 
                +  | 
            |
| 85 | 
                +    func bindViewModelToCollectionView() {
               | 
            |
| 86 | 
                + viewModel.content  | 
            |
| 87 | 
                + .bind(to: collectionView.rx.items(dataSource: dataSource))  | 
            |
| 88 | 
                + .disposed(by: disposeBag)  | 
            |
| 89 | 
                + }  | 
            |
| 90 | 
                +  | 
            |
| 91 | 
                +    func bindCollectionViewDelegate() {
               | 
            |
| 92 | 
                + collectionView.rx.setDelegate(self).disposed(by: disposeBag)  | 
            |
| 93 | 
                + }  | 
            |
| 94 | 
                +  | 
            |
| 95 | 
                +    func bindCollectionViewToViewModel() {
               | 
            |
| 96 | 
                + collectionView.rx.willDisplayCell  | 
            |
| 97 | 
                + .asDriver()  | 
            |
| 98 | 
                +            .drive(onNext: { [unowned self] in self.viewModel.willShow(index: $0.at.row) })
               | 
            |
| 99 | 
                + .disposed(by: disposeBag)  | 
            |
| 100 | 
                + }  | 
            |
| 101 | 
                +}  | 
            |
| 43 | 102 | 
                 | 
            
| 44 | 
                - // MARK: Storyboard button function  | 
            |
| 103 | 
                +/// storyboard button action  | 
            |
| 104 | 
                +extension PhotoPreviewViewController {
               | 
            |
| 45 | 105 | 
                     @IBAction  func back() {
               | 
            
| 46 | 
                - _ = navigationController?.popViewController(animated: true)  | 
            |
| 47 | 
                -        guard let ctl = navigationController?.viewControllers.last as? PhotoDetailViewController else {
               | 
            |
| 48 | 
                - return  | 
            |
| 49 | 
                - }  | 
            |
| 50 | 
                -// ctl.currentPhotoIndex = currentPageIndex  | 
            |
| 51 | 
                -// ctl.tableView.reloadData()  | 
            |
| 106 | 
                + navigationController?.popViewController(animated: true)  | 
            |
| 52 | 107 | 
                }  | 
            
| 53 | 108 | 
                     @IBAction func rotateTheImage(_ sender: UIButton) {
               | 
            
| 54 | 
                -        guard let cell = collectionView.cellForItem(at: IndexPath(item: currentPageIndex, section: 0)) as? ImageCell else {
               | 
            |
| 109 | 
                +        guard let cell = collectionView.cellForItem(at: IndexPath(item: viewModel.currIndex, section: 0)) as? ImageCell else {
               | 
            |
| 55 | 110 | 
                return  | 
            
| 56 | 111 | 
                }  | 
            
| 57 | 112 | 
                         UIView.beginAnimations("image.rotate", context: nil)
               | 
            
                @@ -71,54 +126,14 @@ final class ShowFullPicController: UIViewController {
               | 
            ||
| 71 | 126 | 
                }  | 
            
| 72 | 127 | 
                }  | 
            
| 73 | 128 | 
                }  | 
            
| 129 | 
                +  | 
            |
| 74 | 130 | 
                 | 
            
| 75 | 
                -    @IBAction func load() {
               | 
            |
| 76 | 
                -        guard let cell = collectionView.cellForItem(at: IndexPath(item: currentPageIndex, section: 0)) as? ImageCell else {
               | 
            |
| 77 | 
                -// FFToastView.showToast(inView: view, withText: "未检测到图片")  | 
            |
| 78 | 
                - return  | 
            |
| 79 | 
                - }  | 
            |
| 80 | 
                -        guard let image = cell.photoImage.image else {
               | 
            |
| 81 | 
                -// FFToastView.showToast(inView: view, withText: "未检测到图片")  | 
            |
| 82 | 
                - return  | 
            |
| 83 | 
                - }  | 
            |
| 84 | 
                - UIImageWriteToSavedPhotosAlbum(image, self, #selector(image(_:didFinishSavingWithError:contextInfo:)), nil)  | 
            |
| 85 | 
                - }  | 
            |
| 86 | 
                -  | 
            |
| 87 | 
                -    @objc func image(_ image: UIImage?, didFinishSavingWithError error: NSError?, contextInfo info: UnsafeMutableRawPointer) {
               | 
            |
| 88 | 
                -        if error != nil {
               | 
            |
| 89 | 
                -// FFToastView.showToast(inView: view, withText: "保存图片失败")  | 
            |
| 90 | 
                -        } else {
               | 
            |
| 91 | 
                -// FFToastView.showImageToast(inView: view, withText: "已保存图片到相册", withImage: "提示弹窗-勾")  | 
            |
| 92 | 
                - }  | 
            |
| 93 | 
                -  | 
            |
| 94 | 
                - }  | 
            |
| 95 | 131 | 
                }  | 
            
| 96 | 132 | 
                 | 
            
| 97 | 133 | 
                // MARK: UICollectionView delegate  | 
            
| 98 | 
                -extension ShowFullPicController: UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
               | 
            |
| 99 | 
                -  | 
            |
| 100 | 
                -    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
               | 
            |
| 101 | 
                - return shufflingImage.count > datas.count ? shufflingImage.count : datas.count  | 
            |
| 102 | 
                - }  | 
            |
| 103 | 
                -  | 
            |
| 104 | 
                -    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
               | 
            |
| 105 | 
                - let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "imageCell", for: indexPath) as! ImageCell  | 
            |
| 106 | 
                -        if shufflingImage.count <= 0 {
               | 
            |
| 107 | 
                - let data = datas[indexPath.item]  | 
            |
| 108 | 
                - let urlStr = data.murl.isEmpty ? data.photo_url : data.murl  | 
            |
| 109 | 
                - cell.setModel(url: urlStr)  | 
            |
| 110 | 
                -        } else {
               | 
            |
| 111 | 
                - cell.setModel(url: shufflingImage[indexPath.row])  | 
            |
| 112 | 
                - }  | 
            |
| 113 | 
                - return cell  | 
            |
| 114 | 
                - }  | 
            |
| 134 | 
                +extension PhotoPreviewViewController: UICollectionViewDelegateFlowLayout {
               | 
            |
| 115 | 135 | 
                 | 
            
| 116 | 136 | 
                     func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
               | 
            
| 117 | 137 | 
                return CGSize(width: collectionView.width, height: collectionView.height - 20)  | 
            
| 118 | 138 | 
                }  | 
            
| 119 | 
                -  | 
            |
| 120 | 
                -    func scrollViewDidScroll(_ scrollView: UIScrollView) {
               | 
            |
| 121 | 
                - let page = Int(scrollView.contentOffset.x / (collectionView.width))  | 
            |
| 122 | 
                - currentPageIndex = page  | 
            |
| 123 | 
                - }  | 
            |
| 124 | 139 | 
                }  | 
            
                @@ -9,13 +9,21 @@  | 
            ||
| 9 | 9 | 
                import UIKit  | 
            
| 10 | 10 | 
                 | 
            
| 11 | 11 | 
                 class ShareView: UIView {
               | 
            
| 12 | 
                +  | 
            |
| 13 | 
                +}  | 
            |
| 14 | 
                +  | 
            |
| 12 | 15 | 
                 | 
            
| 13 | 
                - /*  | 
            |
| 14 | 
                - // Only override draw() if you perform custom drawing.  | 
            |
| 15 | 
                - // An empty implementation adversely affects performance during animation.  | 
            |
| 16 | 
                -    override func draw(_ rect: CGRect) {
               | 
            |
| 17 | 
                - // Drawing code  | 
            |
| 18 | 
                - }  | 
            |
| 19 | 
                - */  | 
            |
| 20 | 16 | 
                 | 
            
| 17 | 
                +extension ShareView {
               | 
            |
| 18 | 
                +  | 
            |
| 19 | 
                +    func activateConstraints() {
               | 
            |
| 20 | 
                +  | 
            |
| 21 | 
                + }  | 
            |
| 22 | 
                +  | 
            |
| 23 | 
                +    func activateConstraintsShareView() {
               | 
            |
| 24 | 
                +        guard let superView = superview else { return }
               | 
            |
| 25 | 
                +  | 
            |
| 26 | 
                + self.translatesAutoresizingMaskIntoConstraints = false  | 
            |
| 27 | 
                +  | 
            |
| 28 | 
                + }  | 
            |
| 21 | 29 | 
                }  | 
            
                @@ -1,15 +0,0 @@  | 
            ||
| 1 | 
                -#!/bin/bash  | 
            |
| 2 | 
                -  | 
            |
| 3 | 
                -xcrun simctl shutdown all  | 
            |
| 4 | 
                -  | 
            |
| 5 | 
                -path=$(find ~/Library/Developer/Xcode/DerivedData/Paiai-*/Build/Products/Debug-iphonesimulator -name "Paiai.app" | head -n 1)  | 
            |
| 6 | 
                -echo "${path}"
               | 
            |
| 7 | 
                -  | 
            |
| 8 | 
                -filename=MultiSimConfig.txt  | 
            |
| 9 | 
                -grep -v '^#' $filename | while read -r line  | 
            |
| 10 | 
                -do  | 
            |
| 11 | 
                - echo $line  | 
            |
| 12 | 
                - xcrun instruments -w "$line"  | 
            |
| 13 | 
                - xcrun simctl install booted $path  | 
            |
| 14 | 
                - xcrun simctl launch booted com.Paiai.Paiai  | 
            |
| 15 | 
                -done  |